diff --git a/Misc/NEWS b/Misc/NEWS
index 2599b821d31502c9817f4a7d1cf02a6389458a18..ed646ada53de749dd7291b322424edc493c90a3a 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -48,6 +48,10 @@ Core and Builtins
 Library
 -------
 
+- Issue #21931: msilib.FCICreate() now raises TypeError in the case of a bad
+  argument instead of a ValueError with a bogus FCI error number.
+  Patch by Jeffrey Armstrong.
+
 - Issue #23796: peak and read1 methods of BufferedReader now raise ValueError
   if they called on a closed object. Patch by John Hergenroeder.
 
diff --git a/PC/_msi.c b/PC/_msi.c
index 6a99b40cda8dc0ad3dcd46f3b542135bfcdd5781..86a594310644461a1a7861fdd38981495e894987 100644
--- a/PC/_msi.c
+++ b/PC/_msi.c
@@ -243,8 +243,13 @@ static PyObject* fcicreate(PyObject* obj, PyObject* args)
     for (i=0; i < PyList_GET_SIZE(files); i++) {
         PyObject *item = PyList_GET_ITEM(files, i);
         char *filename, *cabname;
-        if (!PyArg_ParseTuple(item, "ss", &filename, &cabname))
-            goto err;
+
+        if (!PyArg_ParseTuple(item, "ss", &filename, &cabname)) {
+            PyErr_SetString(PyExc_TypeError, "FCICreate expects a list of tuples containing two strings");
+            FCIDestroy(hfci);
+            return NULL;
+        }
+
         if (!FCIAddFile(hfci, filename, cabname, FALSE,
             cb_getnextcabinet, cb_status, cb_getopeninfo,
             tcompTYPE_MSZIP))
@@ -260,7 +265,11 @@ static PyObject* fcicreate(PyObject* obj, PyObject* args)
     Py_INCREF(Py_None);
     return Py_None;
 err:
-    PyErr_Format(PyExc_ValueError, "FCI error %d", erf.erfOper); /* XXX better error type */
+    if(erf.fError)
+        PyErr_Format(PyExc_ValueError, "FCI error %d", erf.erfOper); /* XXX better error type */
+    else
+        PyErr_SetString(PyExc_ValueError, "FCI general error");
+
     FCIDestroy(hfci);
     return NULL;
 }