Index: trunk/ppStack/src/Makefile.am
===================================================================
--- trunk/ppStack/src/Makefile.am	(revision 26928)
+++ trunk/ppStack/src/Makefile.am	(revision 27004)
@@ -47,5 +47,6 @@
 	ppStackCleanup.c	\
 	ppStackPhotometry.c	\
-	ppStackFinish.c
+	ppStackFinish.c		\
+	ppStackErrorCodes.c
 
 noinst_HEADERS = 		\
@@ -53,5 +54,17 @@
 	ppStackLoop.h		\
 	ppStackOptions.h	\
-	ppStackThread.h
+	ppStackThread.h		\
+	ppStackErrorCodes.h
+
+### Error codes.
+BUILT_SOURCES = ppStackErrorCodes.h ppStackErrorCodes.c
+CLEANFILES = ppStackErrorCodes.h ppStackErrorCodes.c
+
+ppStackErrorCodes.h : ppStackErrorCodes.dat ppStackErrorCodes.h.in
+	$(ERRORCODES) --data=ppStackErrorCodes.dat --outdir=. ppStackErrorCodes.h
+
+ppStackErrorCodes.c : ppStackErrorCodes.dat ppStackErrorCodes.c.in ppStackErrorCodes.h
+	$(ERRORCODES) --data=ppStackErrorCodes.dat --outdir=. ppStackErrorCodes.c
+
 
 CLEANFILES = *~
Index: trunk/ppStack/src/ppStack.c
===================================================================
--- trunk/ppStack/src/ppStack.c	(revision 26928)
+++ trunk/ppStack/src/ppStack.c	(revision 27004)
@@ -15,21 +15,10 @@
 int main(int argc, char *argv[])
 {
-    psExit exitValue = PS_EXIT_SUCCESS; // Exit value
+    psLibInit(NULL);
     psTimerStart(TIMER_NAME);
     psTimerStart("PPSTACK_STEPS");
-    psLibInit(NULL);
 
     pmConfig *config = pmConfigRead(&argc, argv, PPSTACK_RECIPE); // Configuration
     if (!config) {
-        psErrorStackPrint(stderr, "Error reading configuration.");
-        exitValue = PS_EXIT_CONFIG_ERROR;
-        goto die;
-    }
-
-    (void) psTraceSetLevel("ppStack", 5);
-
-    if (!ppStackArgumentsSetup(argc, argv, config)) {
-        psErrorStackPrint(stderr, "Error reading arguments.\n");
-        exitValue = PS_EXIT_CONFIG_ERROR;
         goto die;
     }
@@ -38,30 +27,28 @@
 
     if (!pmModelClassInit()) {
-        psErrorStackPrint(stderr, "Error initialising model classes.\n");
-        exitValue = PS_EXIT_PROG_ERROR;
+        psError(PPSTACK_ERR_PROG, false, "Unable to initialise model classes.");
         goto die;
     }
 
     if (!psphotInit()) {
-        psErrorStackPrint(stderr, "Error initialising psphot.\n");
-        exitValue = PS_EXIT_PROG_ERROR;
+        psError(PPSTACK_ERR_PROG, false, "Error initialising psphot.");
+        goto die;
+    }
+
+    (void)psTraceSetLevel("ppStack", 5);
+
+    if (!ppStackArgumentsSetup(argc, argv, config)) {
         goto die;
     }
 
     if (!ppStackCamera(config)) {
-        psErrorStackPrint(stderr, "Error setting up input files.\n");
-        exitValue = PS_EXIT_CONFIG_ERROR;
         goto die;
     }
 
     if (!ppStackArgumentsParse(config)) {
-        psErrorStackPrint(stderr, "Error reading arguments.\n");
-        exitValue = PS_EXIT_CONFIG_ERROR;
         goto die;
     }
 
     if (!ppStackLoop(config)) {
-        psErrorStackPrint(stderr, "Error performing combination.\n");
-        exitValue = PS_EXIT_DATA_ERROR;
         goto die;
     }
@@ -78,4 +65,46 @@
     psLibFinalize();
     pmVisualClose();
+
+    psExit exitValue = PS_EXIT_SUCCESS;        // Exit value for program
+    psErrorCode errorCode = psErrorCodeLast(); // Error code
+    if (errorCode != PS_ERR_NONE) {
+        psErrorStackPrint(stderr, "Unable to perform stack.");
+        switch (errorCode) {
+          case PPSTACK_ERR_UNKNOWN:
+          case PS_ERR_UNKNOWN:
+            exitValue = PS_EXIT_UNKNOWN_ERROR;
+            break;
+          case PS_ERR_IO:
+          case PS_ERR_DB_CLIENT:
+          case PS_ERR_DB_SERVER:
+          case PS_ERR_BAD_FITS:
+          case PS_ERR_OS_CALL_FAILED:
+          case PPSTACK_ERR_IO:
+            exitValue = PS_EXIT_SYS_ERROR;
+            break;
+          case PS_ERR_BAD_PARAMETER_VALUE:
+          case PS_ERR_BAD_PARAMETER_TYPE:
+          case PS_ERR_BAD_PARAMETER_NULL:
+          case PS_ERR_BAD_PARAMETER_SIZE:
+          case PPSTACK_ERR_ARGUMENTS:
+          case PPSTACK_ERR_CONFIG:
+            exitValue = PS_EXIT_CONFIG_ERROR;
+            break;
+          case PPSTACK_ERR_PSF:
+          case PPSTACK_ERR_REJECTED:
+          case PPSTACK_ERR_DATA:
+            exitValue = PS_EXIT_DATA_ERROR;
+            break;
+          case PS_ERR_UNEXPECTED_NULL:
+          case PS_ERR_PROGRAMMING:
+          case PPSTACK_ERR_NOT_IMPLEMENTED:
+          case PPSTACK_ERR_PROG:
+          default:
+            // It's a programming error if we're not dealing with the error correctly
+            exitValue = PS_EXIT_PROG_ERROR;
+            break;
+        }
+    }
+
     exit(exitValue);
 }
Index: trunk/ppStack/src/ppStack.h
===================================================================
--- trunk/ppStack/src/ppStack.h	(revision 26928)
+++ trunk/ppStack/src/ppStack.h	(revision 27004)
@@ -9,4 +9,5 @@
 
 #include "ppStackOptions.h"
+#include "ppStackErrorCodes.h"
 
 // Mask values for inputs
Index: trunk/ppStack/src/ppStackArguments.c
===================================================================
--- trunk/ppStack/src/ppStackArguments.c	(revision 26928)
+++ trunk/ppStack/src/ppStackArguments.c	(revision 27004)
@@ -43,5 +43,5 @@
         value = psMetadataLookup##TYPE(&mdok, recipe, RECIPENAME); \
         if (!mdok) { \
-            psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Unable to find %s in recipe %s", \
+            psError(PPSTACK_ERR_CONFIG, true, "Unable to find %s in recipe %s", \
                 RECIPENAME, PPSTACK_RECIPE); \
             goto ERROR; \
@@ -58,5 +58,5 @@
         value = psMetadataLookup##TYPE(&mdok, recipe, RECIPENAME); \
         if (!mdok) { \
-            psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Unable to find %s in recipe %s", \
+            psError(PPSTACK_ERR_CONFIG, true, "Unable to find %s in recipe %s", \
                 RECIPENAME, PPSTACK_RECIPE); \
             goto ERROR; \
@@ -73,6 +73,6 @@
         name = psMetadataLookupStr(NULL, recipe, RECIPENAME); \
         if (!name) { \
-            psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Unable to find %s in recipe %s", \
-                RECIPENAME, PPSTACK_RECIPE); \
+            psError(PPSTACK_ERR_CONFIG, true, "Unable to find %s in recipe %s", \
+                    RECIPENAME, PPSTACK_RECIPE);                        \
             goto ERROR; \
         } \
@@ -108,5 +108,5 @@
         value = psMetadataLookupStr(NULL, recipe, mdName);
         if (!value) {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Unable to find %s in recipe %s",
+            psError(PPSTACK_ERR_CONFIG, true, "Unable to find %s in recipe %s",
                     mdName, PPSTACK_RECIPE);
             return false;
@@ -207,5 +207,5 @@
         psMetadata *inputs = psMetadataConfigRead(NULL, &numBad, argv[argNum], false); // Input file info
         if (!inputs || numBad > 0) {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false, "Unable to cleanly read MDC file with inputs.");
+            psError(PPSTACK_ERR_ARGUMENTS, false, "Unable to cleanly read MDC file with inputs.");
             return false;
         }
@@ -229,5 +229,5 @@
     int numThreads = psMetadataLookupS32(NULL, arguments, "-threads"); // Number of threads
     if (numThreads > 0 && !psThreadPoolInit(numThreads)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to setup %d threads", numThreads);
+        psError(PPSTACK_ERR_ARGUMENTS, false, "Unable to setup %d threads", numThreads);
         return false;
     }
@@ -247,5 +247,5 @@
     psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSTACK_RECIPE); // Recipe
     if (!recipe) {
-        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find recipe %s", PPSTACK_RECIPE);
+        psError(PPSTACK_ERR_CONFIG, false, "Unable to find recipe %s", PPSTACK_RECIPE);
         goto ERROR;
     }
Index: trunk/ppStack/src/ppStackCamera.c
===================================================================
--- trunk/ppStack/src/ppStackCamera.c	(revision 26928)
+++ trunk/ppStack/src/ppStackCamera.c	(revision 27004)
@@ -30,9 +30,9 @@
         pmFPAfileDefineFromArgs(&found, config, name, "FILENAMES");
     if (!file || !found) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to define file %s from %s", name, filename);
+        psError(psErrorCodeLast(), false, "Unable to define file %s from %s", name, filename);
         return NULL;
     }
     if (file->type != type) {
-        psError(PS_ERR_IO, true, "%s is not of type %s", name, pmFPAfileStringFromType(type));
+        psError(PS_ERR_IO, PPSTACK_ERR_CONFIG, "%s is not of type %s", name, pmFPAfileStringFromType(type));
         return NULL;
     }
@@ -53,5 +53,5 @@
     psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSTACK_RECIPE); // Recipe for ppSim
     if (!recipe) {
-        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find recipe %s", PPSTACK_RECIPE);
+        psError(PPSTACK_ERR_CONFIG, false, "Unable to find recipe %s", PPSTACK_RECIPE);
         return false;
     }
@@ -67,5 +67,5 @@
                                                            "PPSTACK.INPUT.MASK"); // Input masks
         if (!status) {
-            psError(PS_ERR_UNKNOWN, false, "Unable to define input masks from RUN metadata.");
+            psError(psErrorCodeLast(), false, "Unable to define input masks from RUN metadata.");
             psFree(runImages);
             return false;
@@ -76,5 +76,5 @@
                                                           "PPSTACK.INPUT.VARIANCE"); // Input variances
         if (!status) {
-            psError(PS_ERR_UNKNOWN, false, "Unable to define input variances from RUN metadata.");
+            psError(psErrorCodeLast(), false, "Unable to define input variances from RUN metadata.");
             psFree(runImages);
             return false;
@@ -88,10 +88,10 @@
                                                          "PPSTACK.INPUT.SOURCES"); // Input sources
         if (!status) {
-            psError(PS_ERR_UNKNOWN, false, "Unable to define input sources from RUN metadata.");
+            psError(psErrorCodeLast(), false, "Unable to define input sources from RUN metadata.");
             psFree(runImages);
             return false;
         }
         if (!runSrc) {
-            psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to define input sources from RUN metadata.");
+            psError(PPSTACK_ERR_CONFIG, true, "Unable to define input sources from RUN metadata.");
             psFree(runImages);
             return false;
@@ -104,5 +104,5 @@
                                                          "PPSTACK.INPUT.PSF"); // Input PSFs
                 if (!status) {
-                    psError(PS_ERR_UNKNOWN, false, "Unable to define input PSFs from RUN metadata.");
+                    psError(psErrorCodeLast(), false, "Unable to define input PSFs from RUN metadata.");
                     psFree(runImages);
                     return false;
@@ -118,10 +118,11 @@
                                                                     "PPSTACK.CONV.KERNEL"); // Conv'n kernels
                 if (!status) {
-                    psError(PS_ERR_UNKNOWN, false, "Unable to define convolution kernels from RUN metadata.");
+                    psError(psErrorCodeLast(), false,
+                            "Unable to define convolution kernels from RUN metadata.");
                     psFree(runImages);
                     return false;
                 }
                 if (!runKernel) {
-                    psError(PS_ERR_UNEXPECTED_NULL, true,
+                    psError(PPSTACK_ERR_CONFIG, true,
                             "Unable to define convolution kernels from RUN metadata.");
                     psFree(runImages);
@@ -137,5 +138,5 @@
         psMetadata *inputs = psMetadataLookupMetadata(NULL, config->arguments, "INPUTS"); // The inputs info
         if (!inputs) {
-            psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find inputs.");
+            psError(PPSTACK_ERR_ARGUMENTS, false, "Unable to find inputs.");
             return false;
         }
@@ -145,5 +146,5 @@
         while ((item = psMetadataGetAndIncrement(iter))) {
             if (item->type != PS_DATA_METADATA) {
-                psError(PS_ERR_BAD_PARAMETER_TYPE, true,
+                psError(PPSTACK_ERR_ARGUMENTS, true,
                         "Component %s of the input metadata is not of type METADATA", item->name);
                 psFree(iter);
@@ -155,5 +156,5 @@
             psString image = psMetadataLookupStr(NULL, input, "IMAGE"); // Name of image
             if (!image || strlen(image) == 0) {
-                psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Component %s lacks IMAGE of type STR", item->name);
+                psError(PPSTACK_ERR_ARGUMENTS, true, "Component %s lacks IMAGE of type STR", item->name);
                 psFree(iter);
                 return false;
@@ -169,5 +170,5 @@
                                               image, PM_FPA_FILE_IMAGE); // File for image
             if (!imageFile) {
-                psError(PS_ERR_UNKNOWN, false, "Unable to define file from image %d (%s)", i, image);
+                psError(psErrorCodeLast(), false, "Unable to define file from image %d (%s)", i, image);
                 return false;
             }
@@ -175,5 +176,5 @@
             if (mask && strlen(mask) > 0 &&
                 !defineFile(config, imageFile, "PPSTACK.INPUT.MASK", mask, PM_FPA_FILE_MASK)) {
-                psError(PS_ERR_UNKNOWN, false, "Unable to define file from mask %d (%s)", i, mask);
+                psError(psErrorCodeLast(), false, "Unable to define file from mask %d (%s)", i, mask);
                 return false;
             }
@@ -183,5 +184,5 @@
                 if (!defineFile(config, imageFile, "PPSTACK.INPUT.VARIANCE", variance,
                                 PM_FPA_FILE_VARIANCE)) {
-                    psError(PS_ERR_UNKNOWN, false,
+                    psError(psErrorCodeLast(), false,
                             "Unable to define file from variance %d (%s)", i, variance);
                     return false;
@@ -195,19 +196,19 @@
                     havePSFs = true;
                     if (!defineFile(config, imageFile, "PPSTACK.INPUT.PSF", psf, PM_FPA_FILE_PSF)) {
-                        psError(PS_ERR_UNKNOWN, false, "Unable to define file from psf %d (%s)", i, psf);
+                        psError(psErrorCodeLast(), false, "Unable to define file from psf %d (%s)", i, psf);
                         return false;
                     }
                 }
             } else if (havePSFs) {
-                psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find PSF %d", i);
+                psError(PPSTACK_ERR_CONFIG, true, "Unable to find PSF %d", i);
                 return false;
             }
 
             if (!sources || strlen(sources) == 0) {
-                psError(PS_ERR_UNEXPECTED_NULL, true, "SOURCES not provided for file %d", i);
+                psError(PPSTACK_ERR_CONFIG, true, "SOURCES not provided for file %d", i);
                 return false;
             }
             if (!defineFile(config, imageFile, "PPSTACK.INPUT.SOURCES", sources, PM_FPA_FILE_CMF)) {
-                psError(PS_ERR_UNKNOWN, false, "Unable to define file from sources %d (%s)",
+                psError(psErrorCodeLast(), false, "Unable to define file from sources %d (%s)",
                         i, sources);
                 return false;
@@ -217,5 +218,6 @@
                 pmFPAfile *kernel = pmFPAfileDefineOutput(config, imageFile->fpa, "PPSTACK.CONV.KERNEL");
                 if (!kernel) {
-                    psError(PS_ERR_IO, false, _("Unable to generate output file from PPSTACK.CONV.KERNEL"));
+                    psError(psErrorCodeLast(), false,
+                            "Unable to generate output file from PPSTACK.CONV.KERNEL");
                     return false;
                 }
@@ -235,5 +237,5 @@
     pmFPA *outFPA = pmFPAConstruct(config->camera, config->cameraName); // FPA to contain the output
     if (!outFPA) {
-        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to construct an FPA from camera configuration.");
+        psError(psErrorCodeLast(), false, "Unable to construct an FPA from camera configuration.");
         return false;
     }
@@ -241,9 +243,9 @@
     psFree(outFPA);                        // Drop reference
     if (!output) {
-        psError(PS_ERR_IO, false, _("Unable to generate output file from PPSTACK.OUTPUT"));
+        psError(psErrorCodeLast(), false, _("Unable to generate output file from PPSTACK.OUTPUT"));
         return false;
     }
     if (output->type != PM_FPA_FILE_IMAGE) {
-        psError(PS_ERR_IO, true, "PPSTACK.OUTPUT is not of type IMAGE");
+        psError(PPSTACK_ERR_CONFIG, true, "PPSTACK.OUTPUT is not of type IMAGE");
         return false;
     }
@@ -251,5 +253,5 @@
 
     if (!pmFPAAddSourceFromFormat(outFPA, "Stack", output->format)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to generate output FPA.");
+        psError(psErrorCodeLast(), false, "Unable to generate output FPA.");
         return false;
     }
@@ -258,9 +260,9 @@
     pmFPAfile *outMask = pmFPAfileDefineOutput(config, output->fpa, "PPSTACK.OUTPUT.MASK");
     if (!outMask) {
-        psError(PS_ERR_IO, false, _("Unable to generate output file from PPSTACK.OUTPUT.MASK"));
+        psError(psErrorCodeLast(), false, _("Unable to generate output file from PPSTACK.OUTPUT.MASK"));
         return false;
     }
     if (outMask->type != PM_FPA_FILE_MASK) {
-        psError(PS_ERR_IO, true, "PPSTACK.OUTPUT.MASK is not of type MASK");
+        psError(PPSTACK_ERR_CONFIG, true, "PPSTACK.OUTPUT.MASK is not of type MASK");
         return false;
     }
@@ -271,9 +273,9 @@
         pmFPAfile *outVariance = pmFPAfileDefineOutput(config, output->fpa, "PPSTACK.OUTPUT.VARIANCE");
         if (!outVariance) {
-            psError(PS_ERR_IO, false, _("Unable to generate output file from PPSTACK.OUTPUT.VARIANCE"));
+            psError(psErrorCodeLast(), false, "Unable to generate output file from PPSTACK.OUTPUT.VARIANCE");
             return false;
         }
         if (outVariance->type != PM_FPA_FILE_VARIANCE) {
-            psError(PS_ERR_IO, true, "PPSTACK.OUTPUT.VARIANCE is not of type VARIANCE");
+            psError(PPSTACK_ERR_CONFIG, true, "PPSTACK.OUTPUT.VARIANCE is not of type VARIANCE");
             return false;
         }
@@ -284,9 +286,9 @@
         pmFPAfile *targetPSF = pmFPAfileDefineOutput(config, output->fpa, "PPSTACK.TARGET.PSF");
         if (!targetPSF) {
-            psError(PS_ERR_IO, false, _("Unable to generate output file from PPSTACK.TARGET.PSF"));
+            psError(psErrorCodeLast(), false, _("Unable to generate output file from PPSTACK.TARGET.PSF"));
             return false;
         }
         if (targetPSF->type != PM_FPA_FILE_PSF) {
-            psError(PS_ERR_IO, true, "PPSTACK.TARGET.PSF is not of type PSF");
+            psError(PPSTACK_ERR_CONFIG, true, "PPSTACK.TARGET.PSF is not of type PSF");
             return false;
         }
@@ -298,5 +300,5 @@
     pmFPA *unconvFPA = pmFPAConstruct(config->camera, config->cameraName); // FPA to contain unconvolved output
     if (!unconvFPA) {
-        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to construct an FPA from camera configuration.");
+        psError(psErrorCodeLast(), false, "Unable to construct an FPA from camera configuration.");
         return false;
     }
@@ -304,9 +306,9 @@
     psFree(unconvFPA);                  // Drop reference
     if (!unConv) {
-        psError(PS_ERR_IO, false, _("Unable to generate output file from PPSTACK.UNCONV"));
+        psError(psErrorCodeLast(), false, _("Unable to generate output file from PPSTACK.UNCONV"));
         return false;
     }
     if (unConv->type != PM_FPA_FILE_IMAGE) {
-        psError(PS_ERR_IO, true, "PPSTACK.UNCONV is not of type IMAGE");
+        psError(PPSTACK_ERR_CONFIG, true, "PPSTACK.UNCONV is not of type IMAGE");
         return false;
     }
@@ -314,5 +316,5 @@
 
     if (!pmFPAAddSourceFromFormat(unconvFPA, "Stack", unConv->format)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to generate output FPA.");
+        psError(psErrorCodeLast(), false, "Unable to generate output FPA.");
         return false;
     }
@@ -321,9 +323,9 @@
     pmFPAfile *unconvMask = pmFPAfileDefineOutput(config, unconvFPA, "PPSTACK.UNCONV.MASK");
     if (!unconvMask) {
-        psError(PS_ERR_IO, false, _("Unable to generate output file from PPSTACK.UNCONV.MASK"));
+        psError(psErrorCodeLast(), false, _("Unable to generate output file from PPSTACK.UNCONV.MASK"));
         return false;
     }
     if (unconvMask->type != PM_FPA_FILE_MASK) {
-        psError(PS_ERR_IO, true, "PPSTACK.UNCONV.MASK is not of type MASK");
+        psError(PPSTACK_ERR_CONFIG, true, "PPSTACK.UNCONV.MASK is not of type MASK");
         return false;
     }
@@ -334,9 +336,9 @@
         pmFPAfile *unconvVariance = pmFPAfileDefineOutput(config, unconvFPA, "PPSTACK.UNCONV.VARIANCE");
         if (!unconvVariance) {
-            psError(PS_ERR_IO, false, _("Unable to generate output file from PPSTACK.UNCONV.VARIANCE"));
+            psError(psErrorCodeLast(), false, "Unable to generate output file from PPSTACK.UNCONV.VARIANCE");
             return false;
         }
         if (unconvVariance->type != PM_FPA_FILE_VARIANCE) {
-            psError(PS_ERR_IO, true, "PPSTACK.UNCONV.VARIANCE is not of type VARIANCE");
+            psError(PPSTACK_ERR_CONFIG, true, "PPSTACK.UNCONV.VARIANCE is not of type VARIANCE");
             return false;
         }
@@ -348,9 +350,9 @@
     pmFPAfile *jpeg1 = pmFPAfileDefineOutput(config, NULL, "PPSTACK.OUTPUT.JPEG1");
     if (!jpeg1) {
-        psError(PS_ERR_IO, false, _("Unable to generate output file from PPSTACK.OUTPUT.JPEG1"));
+        psError(psErrorCodeLast(), false, _("Unable to generate output file from PPSTACK.OUTPUT.JPEG1"));
         return false;
     }
     if (jpeg1->type != PM_FPA_FILE_JPEG) {
-        psError(PS_ERR_IO, true, "PPSTACK.OUTPUT.JPEG1 is not of type JPEG");
+        psError(PPSTACK_ERR_CONFIG, true, "PPSTACK.OUTPUT.JPEG1 is not of type JPEG");
         return false;
     }
@@ -358,9 +360,9 @@
     pmFPAfile *jpeg2 = pmFPAfileDefineOutput(config, NULL, "PPSTACK.OUTPUT.JPEG2");
     if (!jpeg2) {
-        psError(PS_ERR_IO, false, _("Unable to generate output file from PPSTACK.OUTPUT.JPEG2"));
+        psError(psErrorCodeLast(), false, _("Unable to generate output file from PPSTACK.OUTPUT.JPEG2"));
         return false;
     }
     if (jpeg2->type != PM_FPA_FILE_JPEG) {
-        psError(PS_ERR_IO, true, "PPSTACK.OUTPUT.JPEG2 is not of type JPEG");
+        psError(PPSTACK_ERR_CONFIG, true, "PPSTACK.OUTPUT.JPEG2 is not of type JPEG");
         return false;
     }
@@ -377,13 +379,13 @@
         pmFPAfile *psphotInput = pmFPAfileDefineFromFPA(config, output->fpa, 1, 1, "PSPHOT.INPUT");
         if (!psphotInput) {
-            psError(PS_ERR_IO, false, _("Unable to generate output file from PSPHOT.INPUT"));
-            return false;
-        }
-	// specify the number of psphot input images
-	psMetadataAddS32 (config->arguments, PS_LIST_TAIL, "PSPHOT.INPUT.NUM", PS_META_REPLACE, "number of inputs", 1);
+            psError(psErrorCodeLast(), false, _("Unable to generate output file from PSPHOT.INPUT"));
+            return false;
+        }
+        // specify the number of psphot input images
+        psMetadataAddS32 (config->arguments, PS_LIST_TAIL, "PSPHOT.INPUT.NUM", PS_META_REPLACE, "number of inputs", 1);
 
         // Define associated psphot input/output files
         if (!psphotDefineFiles(config, psphotInput)) {
-            psError(PSPHOT_ERR_CONFIG, false,
+            psError(psErrorCodeLast(), false,
                     "Trouble defining the additional input/output files for psphot");
             return false;
@@ -393,9 +395,9 @@
         pmFPAfile *outPSF = pmFPAfileDefineOutputFromFile(config, output, "PSPHOT.PSF.SAVE");
         if (!outPSF) {
-            psError(PS_ERR_IO, false, _("Unable to generate output file from PSPHOT.PSF.SAVE"));
+            psError(psErrorCodeLast(), false, _("Unable to generate output file from PSPHOT.PSF.SAVE"));
             return false;
         }
         if (outPSF->type != PM_FPA_FILE_PSF) {
-            psError(PS_ERR_IO, true, "PSPHOT.PSF.SAVE is not of type PSF");
+            psError(PPSTACK_ERR_CONFIG, true, "PSPHOT.PSF.SAVE is not of type PSF");
             return false;
         }
Index: trunk/ppStack/src/ppStackCleanup.c
===================================================================
--- trunk/ppStack/src/ppStackCleanup.c	(revision 26928)
+++ trunk/ppStack/src/ppStackCleanup.c	(revision 27004)
@@ -50,5 +50,5 @@
         if (!pmReadoutRebin(ro1, options->outRO, maskValue, bin1, bin1) ||
             !pmReadoutRebin(ro2, ro1, 0, bin2, bin2)) {
-            psError(PS_ERR_UNKNOWN, false, "Unable to bin output.");
+            psError(PPSTACK_ERR_DATA, false, "Unable to bin output.");
             psFree(ro1);
             psFree(ro2);
Index: trunk/ppStack/src/ppStackCombineFinal.c
===================================================================
--- trunk/ppStack/src/ppStackCombineFinal.c	(revision 26928)
+++ trunk/ppStack/src/ppStackCombineFinal.c	(revision 27004)
@@ -31,5 +31,5 @@
         if (!status) {
             // Something went wrong
-            psError(PS_ERR_UNKNOWN, false, "Unable to read chunk %d", numChunk);
+            psError(psErrorCodeLast(), false, "Unable to read chunk %d", numChunk);
             return false;
         }
@@ -55,5 +55,5 @@
 
     if (!psThreadPoolWait(true)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to do final combination.");
+        psError(psErrorCodeLast(), false, "Unable to do final combination.");
         return false;
     }
@@ -126,5 +126,5 @@
     pmHDU *hdu = pmHDUFromCell(target->parent);
     if (!hdu) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to find HDU for output.");
+        psError(PPSTACK_ERR_PROG, false, "Unable to find HDU for output.");
         return false;
     }
Index: trunk/ppStack/src/ppStackCombineInitial.c
===================================================================
--- trunk/ppStack/src/ppStackCombineInitial.c	(revision 26928)
+++ trunk/ppStack/src/ppStackCombineInitial.c	(revision 27004)
@@ -20,5 +20,5 @@
     if (!options->convolve) {
         // No need to do initial combination when we haven't convolved
-	// XXX either allocate inspect and rejected here, or do not require them downstream
+        // XXX either allocate inspect and rejected here, or do not require them downstream
         return true;
     }
@@ -37,5 +37,5 @@
         if (!status) {
             // Something went wrong
-            psError(PS_ERR_UNKNOWN, false, "Unable to read chunk %d", numChunk);
+            psError(psErrorCodeLast(), false, "Unable to read chunk %d", numChunk);
             return false;
         }
@@ -57,5 +57,5 @@
 
     if (!psThreadPoolWait(false)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to do initial combination.");
+        psError(psErrorCodeLast(), false, "Unable to do initial combination.");
         return false;
     }
Index: trunk/ppStack/src/ppStackCombinePrepare.c
===================================================================
--- trunk/ppStack/src/ppStackCombinePrepare.c	(revision 26928)
+++ trunk/ppStack/src/ppStackCombinePrepare.c	(revision 27004)
@@ -20,5 +20,5 @@
     ppStackThread *thread = stack->threads->data[0]; // Representative thread
     if (!pmReadoutStackSetOutputSize(&col0, &row0, &numCols, &numRows, thread->readouts)) {
-        psError(PS_ERR_UNKNOWN, false, "problem setting output readout size.");
+        psError(PPSTACK_ERR_ARGUMENTS, false, "problem setting output readout size.");
         return false;
     }
@@ -45,5 +45,5 @@
 
     if (!pmReadoutStackDefineOutput(options->outRO, col0, row0, numCols, numRows, true, true, maskBad)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to prepare output.");
+        psError(PPSTACK_ERR_ARGUMENTS, false, "Unable to prepare output.");
         return false;
     }
Index: trunk/ppStack/src/ppStackConvolve.c
===================================================================
--- trunk/ppStack/src/ppStackConvolve.c	(revision 26928)
+++ trunk/ppStack/src/ppStackConvolve.c	(revision 27004)
@@ -82,5 +82,5 @@
         } else if (options->numCols != readout->image->numCols ||
                    options->numRows != readout->image->numRows) {
-            psError(PS_ERR_UNKNOWN, true, "Sizes of input images don't match: %dx%d vs %dx%d",
+            psError(PPSTACK_ERR_ARGUMENTS, true, "Sizes of input images don't match: %dx%d vs %dx%d",
                     readout->image->numCols, readout->image->numRows, options->numCols, options->numRows);
             psFree(rng);
@@ -94,9 +94,23 @@
         options->origCovars->data[i] = psMemIncrRefCounter(readout->covariance);
         if (!ppStackMatch(readout, options, i, config)) {
-	    // XXX many things can cause a failure of ppStackMatch -- should some be handled differently? 
-            psErrorStackPrint(stderr, "Unable to match image %d --- ignoring.", i);
-            options->inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i] |= PPSTACK_MASK_MATCH;
-            psErrorClear();
-            continue;
+            // XXX many things can cause a failure of ppStackMatch -- should some be handled differently?
+            psErrorCode error = psErrorCodeLast(); // Error code
+            switch (error) {
+                // Fatal errors
+              case PM_ERR_CONFIG:
+              case PPSTACK_ERR_CONFIG:
+              case PPSTACK_ERR_IO:
+                psError(error, false, "Unable to match image %d due to fatal error.", i);
+                return false;
+                // Non-fatal errors
+              case PM_ERR_STAMPS:
+              case PM_ERR_SMALL_AREA:
+              case PPSTACK_ERR_DATA:
+              default:
+                psErrorStackPrint(stderr, "Unable to match image %d --- ignoring.", i);
+                options->inputMask->data.PS_TYPE_VECTOR_MASK_DATA[i] |= PPSTACK_MASK_MATCH;
+                psErrorClear();
+                continue;
+            }
         }
         options->convCovars->data[i] = psMemIncrRefCounter(readout->covariance);
@@ -136,5 +150,5 @@
         assert(hdu);
         if (!ppStackWriteImage(options->convImages->data[i], hdu->header, readout->image, config)) {
-            psError(PS_ERR_IO, false, "Unable to write convolved image %d", i);
+            psError(PPSTACK_ERR_IO, false, "Unable to write convolved image %d", i);
             psFree(fpaList);
             psFree(cellList);
@@ -145,5 +159,5 @@
         pmConfigMaskWriteHeader(config, maskHeader);
         if (!ppStackWriteImage(options->convMasks->data[i], maskHeader, readout->mask, config)) {
-            psError(PS_ERR_IO, false, "Unable to write convolved mask %d", i);
+            psError(PPSTACK_ERR_IO, false, "Unable to write convolved mask %d", i);
             psFree(fpaList);
             psFree(cellList);
@@ -154,5 +168,5 @@
         psFree(maskHeader);
         if (!ppStackWriteImage(options->convVariances->data[i], hdu->header, readout->variance, config)) {
-            psError(PS_ERR_IO, false, "Unable to write convolved variance %d", i);
+            psError(PPSTACK_ERR_IO, false, "Unable to write convolved variance %d", i);
             psFree(fpaList);
             psFree(cellList);
@@ -208,5 +222,5 @@
 
     if (numGood == 0) {
-        psError(PS_ERR_UNKNOWN, false, "No good images to combine.");
+        psError(PPSTACK_ERR_REJECTED, false, "No good images to combine.");
         psFree(fpaList);
         psFree(cellList);
@@ -257,5 +271,5 @@
         assert(values->n == numGood);
         if (!psVectorSortInPlace(values)) {
-            psError(PS_ERR_UNKNOWN, false, "Unable to sort vector.");
+            psError(PPSTACK_ERR_PROG, false, "Unable to sort vector.");
             psFree(values);
             return false;
@@ -295,5 +309,5 @@
 
     if (numGood == 0) {
-        psError(PS_ERR_UNKNOWN, false, "No good images to combine.");
+        psError(PPSTACK_ERR_REJECTED, false, "No good images to combine.");
         return false;
     }
Index: trunk/ppStack/src/ppStackErrorCodes.c.in
===================================================================
--- trunk/ppStack/src/ppStackErrorCodes.c.in	(revision 27004)
+++ trunk/ppStack/src/ppStackErrorCodes.c.in	(revision 27004)
@@ -0,0 +1,37 @@
+/** @file ppStackErrorCodes.c.in
+ *
+ *  @brief
+ *
+ *  @ingroup ppStack
+ *
+ *  @author IfA
+ *  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2009-02-05 20:44:04 $
+ *  Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+#include "pslib.h"
+#include "ppStackErrorCodes.h"
+
+/*
+ * The line
+    { PPSTACK_ERR_$X{ErrorCode}, "$X{ErrorDescription}"},
+ * (without the Xs)
+ * will be replaced by values from errorCodes.dat
+ */
+void ppStackErrorRegister(void)
+{
+    static psErrorDescription errors[] = {
+       { PPSTACK_ERR_BASE, "First value we use; lower values belong to psLib" },
+       { PPSTACK_ERR_${ErrorCode}, "${ErrorDescription}"},
+    };
+    static int nerror = PPSTACK_ERR_NERROR - PPSTACK_ERR_BASE; ///< number of values in enum
+
+    for (int i = 0; i < nerror; i++) {
+       psErrorDescription *tmp = psAlloc(sizeof(psErrorDescription));
+       *tmp = errors[i];
+       psErrorRegister(tmp, 1);
+       psFree(tmp);                     /* it's on the internal list */
+    }
+    nerror = 0;                                 // don't register more than once
+}
Index: trunk/ppStack/src/ppStackErrorCodes.dat
===================================================================
--- trunk/ppStack/src/ppStackErrorCodes.dat	(revision 27004)
+++ trunk/ppStack/src/ppStackErrorCodes.dat	(revision 27004)
@@ -0,0 +1,13 @@
+#
+# This file is used to generate ppStackErrorClasses.h
+#
+BASE = 13000		First value we use; lower values belong to psLib
+UNKNOWN			Unknown ppSub error code
+NOT_IMPLEMENTED		Desired feature is not yet implemented
+ARGUMENTS		Incorrect arguments
+CONFIG			Problem in configure files
+IO			Problem in FITS I/O
+DATA                    Problem in data values
+PSF			Problem determining PSF
+REJECTED		All images rejected
+PROG			Programming error
Index: trunk/ppStack/src/ppStackErrorCodes.h.in
===================================================================
--- trunk/ppStack/src/ppStackErrorCodes.h.in	(revision 27004)
+++ trunk/ppStack/src/ppStackErrorCodes.h.in	(revision 27004)
@@ -0,0 +1,30 @@
+/** @file ppStackErrorCodes.h.in
+ *
+ *  @brief
+ *
+ *  @ingroup ppStack
+ *
+ *  @author IfA
+ *  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2009-02-05 20:44:04 $
+ *  Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+#if !defined(PPSTACK_ERROR_CODES_H)
+#define PPSTACK_ERROR_CODES_H
+/*
+ * The line
+ *  PPSTACK_ERR_$X{ErrorCode},
+ * (without the X)
+ *
+ * will be replaced by values from errorCodes.dat
+ */
+typedef enum {
+    PPSTACK_ERR_BASE = 14000,
+    PPSTACK_ERR_${ErrorCode},
+    PPSTACK_ERR_NERROR
+} ppStackErrorCode;
+
+void ppStackErrorRegister(void);
+
+#endif
Index: trunk/ppStack/src/ppStackFiles.c
===================================================================
--- trunk/ppStack/src/ppStackFiles.c	(revision 26928)
+++ trunk/ppStack/src/ppStackFiles.c	(revision 27004)
@@ -115,16 +115,20 @@
     pmFPAview *view = pmFPAviewAlloc(0);// Pointer into FPA hierarchy
     if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
+        psError(PPSTACK_ERR_IO, false, "File checks failed.");
         return NULL;
     }
     view->chip = 0;
     if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
+        psError(PPSTACK_ERR_IO, false, "File checks failed.");
         return NULL;
     }
     view->cell = 0;
     if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
+        psError(PPSTACK_ERR_IO, false, "File checks failed.");
         return NULL;
     }
     view->readout = 0;
     if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
+        psError(PPSTACK_ERR_IO, false, "File checks failed.");
         return NULL;
     }
@@ -141,16 +145,20 @@
     view->chip = view->cell = view->readout = 0;
     if (!pmFPAfileIOChecks(config, view, PM_FPA_AFTER)) {
+        psError(PPSTACK_ERR_IO, false, "File checks failed.");
         return false;
     }
     view->readout = -1;
     if (!pmFPAfileIOChecks(config, view, PM_FPA_AFTER)) {
+        psError(PPSTACK_ERR_IO, false, "File checks failed.");
         return false;
     }
     view->cell = -1;
     if (!pmFPAfileIOChecks(config, view, PM_FPA_AFTER)) {
+        psError(PPSTACK_ERR_IO, false, "File checks failed.");
         return false;
     }
     view->chip = -1;
     if (!pmFPAfileIOChecks(config, view, PM_FPA_AFTER)) {
+        psError(PPSTACK_ERR_IO, false, "File checks failed.");
         return false;
     }
@@ -172,10 +180,10 @@
     psFits *fits = psFitsOpen(resolved, "w");
     if (!fits) {
-        psError(PS_ERR_IO, false, "Unable to open FITS file %s to write image.", resolved);
+        psError(PPSTACK_ERR_IO, false, "Unable to open FITS file %s to write image.", resolved);
         psFree(resolved);
         return false;
     }
     if (!psFitsWriteImage(fits, header, image, 0, NULL)) {
-        psError(PS_ERR_IO, false, "Unable to write FITS image %s.", resolved);
+        psError(PPSTACK_ERR_IO, false, "Unable to write FITS image %s.", resolved);
         psFitsClose(fits);
         psFree(resolved);
@@ -183,5 +191,5 @@
     }
     if (!psFitsClose(fits)) {
-        psError(PS_ERR_IO, false, "Unable to close FITS image %s.", resolved);
+        psError(PPSTACK_ERR_IO, false, "Unable to close FITS image %s.", resolved);
         psFree(resolved);
         return false;
Index: trunk/ppStack/src/ppStackLoop.c
===================================================================
--- trunk/ppStack/src/ppStackLoop.c	(revision 26928)
+++ trunk/ppStack/src/ppStackLoop.c	(revision 27004)
@@ -22,5 +22,5 @@
     psTrace("ppStack", 1, "Setup....\n");
     if (!ppStackSetup(options, config)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to setup.");
+        psError(psErrorCodeLast(), false, "Unable to setup.");
         psFree(options);
         return false;
@@ -33,5 +33,5 @@
     psTrace("ppStack", 1, "Preparation for stacking: merging sources, determining target PSF....\n");
     if (!ppStackPrepare(options, config)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to prepare for stacking.");
+        psError(psErrorCodeLast(), false, "Unable to prepare for stacking.");
         psFree(options);
         return false;
@@ -45,5 +45,5 @@
     psTrace("ppStack", 1, "Convolving inputs to target PSF....\n");
     if (!ppStackConvolve(options, config)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to convolve images.");
+        psError(psErrorCodeLast(), false, "Unable to convolve images.");
         psFree(options);
         return false;
@@ -58,5 +58,5 @@
     ppStackThreadData *stack = ppStackThreadDataSetup(options, config, true);
     if (!stack) {
-        psError(PS_ERR_IO, false, "Unable to initialise stack threads.");
+        psError(psErrorCodeLast(), false, "Unable to initialise stack threads.");
         psFree(options);
         return false;
@@ -65,5 +65,5 @@
     // Prepare for combination
     if (!ppStackCombinePrepare(stack, options, config)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to prepare for combination.");
+        psError(psErrorCodeLast(), false, "Unable to prepare for combination.");
         psFree(stack);
         psFree(options);
@@ -74,5 +74,5 @@
     psTrace("ppStack", 1, "Initial stack of convolved images....\n");
     if (!ppStackCombineInitial(stack, options, config)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to perform initial combination.");
+        psError(psErrorCodeLast(), false, "Unable to perform initial combination.");
         psFree(stack);
         psFree(options);
@@ -86,5 +86,5 @@
     psTrace("ppStack", 1, "Reject pixels....\n");
     if (!ppStackReject(options, config)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to reject pixels.");
+        psError(psErrorCodeLast(), false, "Unable to reject pixels.");
         psFree(stack);
         psFree(options);
@@ -98,5 +98,5 @@
     psTrace("ppStack", 2, "Final stack of convolved images....\n");
     if (!ppStackCombineFinal(options->outRO, stack, options->convCovars, options, config, false, false)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to perform final combination.");
+        psError(psErrorCodeLast(), false, "Unable to perform final combination.");
         psFree(stack);
         psFree(options);
@@ -109,5 +109,5 @@
     psTrace("ppStack", 2, "Cleaning up after combination....\n");
     if (!ppStackCleanup(stack, options, config)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to clean up.");
+        psError(psErrorCodeLast(), false, "Unable to clean up.");
         psFree(stack);
         psFree(options);
@@ -125,5 +125,5 @@
         ppStackThreadData *stack = ppStackThreadDataSetup(options, config, false);
         if (!stack) {
-            psError(PS_ERR_IO, false, "Unable to initialise stack threads.");
+            psError(psErrorCodeLast(), false, "Unable to initialise stack threads.");
             psFree(options);
             return false;
@@ -131,5 +131,5 @@
         psTrace("ppStack", 2, "Stack of unconvolved images....\n");
         if (!ppStackCombineFinal(options->unconvRO, stack, options->origCovars, options, config, false, true)) {
-            psError(PS_ERR_UNKNOWN, false, "Unable to perform unconvolved combination.");
+            psError(psErrorCodeLast(), false, "Unable to perform unconvolved combination.");
             psFree(stack);
             psFree(options);
@@ -147,5 +147,5 @@
     psTrace("ppStack", 1, "Photometering stacked image....\n");
     if (!ppStackPhotometry(options, config)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to perform photometry.");
+        psError(psErrorCodeLast(), false, "Unable to perform photometry.");
         psFree(options);
         return false;
@@ -157,5 +157,5 @@
     psTrace("ppStack", 1, "Finishing up....\n");
     if (!ppStackFinish(options, config)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to finish up.");
+        psError(psErrorCodeLast(), false, "Unable to finish up.");
         psFree(options);
         return false;
Index: trunk/ppStack/src/ppStackMatch.c
===================================================================
--- trunk/ppStack/src/ppStackMatch.c	(revision 26928)
+++ trunk/ppStack/src/ppStackMatch.c	(revision 27004)
@@ -31,10 +31,10 @@
     psFree(resolved);
     if (!fits) {
-        psError(PS_ERR_IO, false, "Unable to open previously produced image: %s", name);
+        psError(PPSTACK_ERR_IO, false, "Unable to open previously produced image: %s", name);
         return false;
     }
     psImage *image = psFitsReadImage(fits, psRegionSet(0,0,0,0), 0); // Image of interest
     if (!image) {
-        psError(PS_ERR_IO, false, "Unable to read previously produced image: %s", name);
+        psError(PPSTACK_ERR_IO, false, "Unable to read previously produced image: %s", name);
         psFitsClose(fits);
         return false;
@@ -150,5 +150,5 @@
     psImage *unbinned = psImageAlloc(numCols, numRows, PS_TYPE_F32); // Unbinned background model
     if (!psImageUnbin(unbinned, binned, binning)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to unbin background model");
+        psError(PPSTACK_ERR_DATA, false, "Unable to unbin background model");
         psFree(unbinned);
         return NULL;
@@ -177,15 +177,15 @@
     int num = psMetadataLookupS32(&mdok, recipe, "RENORM.NUM");
     if (!mdok) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "RENORM.NUM is not set in the recipe");
+        psError(PPSTACK_ERR_CONFIG, true, "RENORM.NUM is not set in the recipe");
         return false;
     }
     float minValid = psMetadataLookupF32(&mdok, recipe, "RENORM.MIN");
     if (!mdok) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "RENORM.MIN is not set in the recipe");
+        psError(PPSTACK_ERR_CONFIG, true, "RENORM.MIN is not set in the recipe");
         return false;
     }
     float maxValid = psMetadataLookupF32(&mdok, recipe, "RENORM.MAX");
     if (!mdok) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "RENORM.MAX is not set in the recipe");
+        psError(PPSTACK_ERR_CONFIG, true, "RENORM.MAX is not set in the recipe");
         return false;
     }
@@ -229,5 +229,5 @@
 
     if (!pmReadoutMaskNonfinite(readout, maskVal)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to mask non-finite pixels in readout.");
+        psError(psErrorCodeLast(), false, "Unable to mask non-finite pixels in readout.");
         return false;
     }
@@ -256,5 +256,5 @@
             psFree(resolved);
             if (!fits || !pmReadoutReadSubtractionKernels(conv, fits)) {
-                psError(PS_ERR_IO, false, "Unable to read previously produced kernel");
+                psError(PPSTACK_ERR_IO, false, "Unable to read previously produced kernel");
                 psFitsClose(fits);
                 return false;
@@ -265,5 +265,5 @@
                 !readImage(&readout->mask, options->convMasks->data[index], config) ||
                 !readImage(&readout->variance, options->convVariances->data[index], config)) {
-                psError(PS_ERR_IO, false, "Unable to read previously produced image.");
+                psError(PPSTACK_ERR_IO, false, "Unable to read previously produced image.");
                 return false;
             }
@@ -326,5 +326,5 @@
             float scaleMax = psMetadataLookupF32(NULL, ppsub, "SCALE.MAX"); // Maximum for scaling
             if (!isfinite(scaleRef) || !isfinite(scaleMin) || !isfinite(scaleMax)) {
-                psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                psError(PPSTACK_ERR_CONFIG, false,
                         "Scale parameters (SCALE.REF=%f, SCALE.MIN=%f, SCALE.MAX=%f) not set in PPSUB recipe.",
                         scaleRef, scaleMin, scaleMax);
@@ -346,5 +346,5 @@
             psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS); // Random number generator
             if (!psImageBackground(bg, NULL, readout->image, readout->mask, maskVal | maskBad, rng)) {
-                psError(PS_ERR_UNKNOWN, false, "Can't measure background for image.");
+                psError(PPSTACK_ERR_DATA, false, "Can't measure background for image.");
                 psFree(fake);
                 psFree(optWidths);
@@ -366,5 +366,5 @@
                                           stampSources, SOURCE_MASK, NULL, NULL, options->psf,
                                           minFlux, footprint + size, false, true)) {
-                psError(PS_ERR_UNKNOWN, false, "Unable to generate fake image with target PSF.");
+                psError(PPSTACK_ERR_DATA, false, "Unable to generate fake image with target PSF.");
                 psFree(fake);
                 psFree(optWidths);
@@ -417,5 +417,5 @@
                                                stride, kernelError, covarFrac, maskVal, maskBad, maskPoor,
                                                poorFrac, badFrac)) {
-                    psError(PS_ERR_UNKNOWN, false, "Unable to convolve images.");
+                    psError(psErrorCodeLast(), false, "Unable to convolve images.");
                     psFree(fake);
                     psFree(optWidths);
@@ -433,5 +433,5 @@
                                                        options->inputSeeing->data.F32[index],
                                                        options->targetSeeing, scaleRef, scaleMin, scaleMax)) {
-                    psError(PS_ERR_UNKNOWN, false, "Unable to scale kernel parameters");
+                    psError(psErrorCodeLast(), false, "Unable to scale kernel parameters");
                     psFree(fake);
                     psFree(optWidths);
@@ -451,5 +451,5 @@
                                         sysError, skyErr, kernelError, covarFrac, maskVal, maskBad, maskPoor,
                                         poorFrac, badFrac, PM_SUBTRACTION_MODE_2)) {
-                    psError(PS_ERR_UNKNOWN, false, "Unable to match images.");
+                    psError(psErrorCodeLast(), false, "Unable to match images.");
                     psFree(fake);
                     psFree(optWidths);
@@ -464,4 +464,5 @@
                 psFree(widthsCopy);
             }
+
 
 #ifdef TESTING
@@ -628,5 +629,5 @@
     // Measure the variance level for the weighting
     if (!psImageBackground(bg, NULL, readout->variance, readout->mask, maskVal | maskBad, rng)) {
-        psError(PS_ERR_UNKNOWN, false, "Can't measure mean variance for image.");
+        psError(PPSTACK_ERR_DATA, false, "Can't measure mean variance for image.");
         psFree(rng);
         psFree(bg);
Index: trunk/ppStack/src/ppStackPSF.c
===================================================================
--- trunk/ppStack/src/ppStackPSF.c	(revision 26928)
+++ trunk/ppStack/src/ppStackPSF.c	(revision 27004)
@@ -28,5 +28,5 @@
     psString maskValStr = psMetadataLookupStr(&mdok, recipe, "MASK.VAL"); // Name of bits to mask going in
     if (!mdok || !maskValStr) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to find MASK.VAL in recipe");
+        psError(PPSTACK_ERR_CONFIG, false, "Unable to find MASK.VAL in recipe");
         return false;
     }
@@ -43,5 +43,5 @@
     pmPSF *psf = pmPSFEnvelope(numCols, numRows, psfs, psfInstances, psfRadius, psfModel, psfOrder, psfOrder, maskVal);
     if (!psf) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to determine output PSF.");
+        psError(PPSTACK_ERR_PSF, false, "Unable to determine output PSF.");
         return NULL;
     }
@@ -50,5 +50,5 @@
     pmPSF *psf = pmPSFBuildSimple("PS_MODEL_PS1_V1", 4.0, 4.0, 0.0, 1.0);
     if (!psf) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to build dummy PSF.");
+        psError(PPSTACK_ERR_PSF, false, "Unable to build dummy PSF.");
         return NULL;
     }
Index: trunk/ppStack/src/ppStackPhotometry.c
===================================================================
--- trunk/ppStack/src/ppStackPhotometry.c	(revision 26928)
+++ trunk/ppStack/src/ppStackPhotometry.c	(revision 27004)
@@ -61,5 +61,5 @@
     psArray *inSources = options->sources;
     if (!inSources) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to find input sources");
+        psError(PPSTACK_ERR_PROG, false, "Unable to find input sources");
         psFree(photView);
         return false;
@@ -83,5 +83,5 @@
         !pmFPAfileDropInternal (config->files, "PSPHOT.BACKMDL.STDEV") ||
         !pmFPAfileDropInternal (config->files, "PSPHOT.BACKGND")) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to drop PSPHOT internal files.");
+        psError(PPSTACK_ERR_PROG, false, "Unable to drop PSPHOT internal files.");
         return false;
     }
@@ -92,6 +92,5 @@
         pmReadout *photRO = pmFPAviewThisReadout(photView, photFile->fpa); // Readout with the sources
         pmDetections *detections = psMetadataLookupPtr(NULL, photRO->analysis, "PSPHOT.DETECTIONS"); // detections
-        if (detections) {
-            psAssert (detections->allSources, "missing sources?");
+        if (detections && detections->allSources) {
             psMetadataAddS32(options->stats, PS_LIST_TAIL, "NUM_SOURCES", 0, "Number of sources detected", detections->allSources->n);
         } else {
Index: trunk/ppStack/src/ppStackPrepare.c
===================================================================
--- trunk/ppStack/src/ppStackPrepare.c	(revision 26928)
+++ trunk/ppStack/src/ppStackPrepare.c	(revision 27004)
@@ -26,15 +26,15 @@
     float zpRadius = psMetadataLookupS32(&mdok, recipe, "PHOT.RADIUS"); // Radius for PHOT measurement
     if (!mdok) {
-        psError(PS_ERR_UNKNOWN, true, "Unable to find PHOT.RADIUS in recipe");
+        psError(PPSTACK_ERR_CONFIG, true, "Unable to find PHOT.RADIUS in recipe");
         return false;
     }
     float zpSigma = psMetadataLookupF32(&mdok, recipe, "PHOT.SIGMA"); // Gaussian sigma for photometry
     if (!mdok) {
-        psError(PS_ERR_UNKNOWN, true, "Unable to find PHOT.SIGMA in recipe");
+        psError(PPSTACK_ERR_CONFIG, true, "Unable to find PHOT.SIGMA in recipe");
         return false;
     }
     float zpFrac = psMetadataLookupF32(&mdok, recipe, "PHOT.FRAC"); // Fraction of good pixels for photometry
     if (!mdok) {
-        psError(PS_ERR_UNKNOWN, true, "Unable to find PHOT.FRAC in recipe");
+        psError(PPSTACK_ERR_CONFIG, true, "Unable to find PHOT.FRAC in recipe");
         return false;
     }
@@ -42,5 +42,5 @@
     psString maskValStr = psMetadataLookupStr(&mdok, recipe, "MASK.VAL"); // Name of bits to mask going in
     if (!mdok || !maskValStr) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to find MASK.VAL in recipe");
+        psError(PPSTACK_ERR_CONFIG, false, "Unable to find MASK.VAL in recipe");
         return false;
     }
@@ -53,5 +53,5 @@
     psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV); // Statistics
     if (!psImageBackground(stats, NULL, image, mask, maskVal, rng)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to measure background for image");
+        psError(PPSTACK_ERR_DATA, false, "Unable to measure background for image");
         psFree(stats);
         psFree(rng);
@@ -148,5 +148,5 @@
             pmPSF *psf = psMetadataLookupPtr(NULL, chip->analysis, "PSPHOT.PSF"); // PSF
             if (!psf) {
-                psError(PS_ERR_UNKNOWN, false, "Unable to find PSF.");
+                psError(PPSTACK_ERR_PROG, false, "Unable to find PSF.");
                 psFree(view);
                 psFree(fileIter);
@@ -163,5 +163,5 @@
             int naxis2 = psMetadataLookupS32(NULL, hdu->header, "NAXIS2"); // Number of rows
             if (naxis1 <= 0 || naxis2 <= 0) {
-                psError(PS_ERR_UNKNOWN, false, "Unable to determine size of image from PSF.");
+                psError(PPSTACK_ERR_PROG, false, "Unable to determine size of image from PSF.");
                 psFree(view);
                 psFree(fileIter);
@@ -183,5 +183,5 @@
             detections = psMetadataLookupPtr(NULL, ro->analysis, "PSPHOT.DETECTIONS"); // Sources
             if (!detections) {
-                psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find source detections in readout.");
+                psError(PPSTACK_ERR_PROG, false, "Unable to find source detections in readout.");
                 return NULL;
             }
@@ -209,5 +209,5 @@
 
             if (!ppStackInputPhotometer(ro, detections->allSources, config)) {
-                psError(PS_ERR_UNKNOWN, false, "Unable to do photometry on input sources");
+                psError(psErrorCodeLast(), false, "Unable to do photometry on input sources");
                 psFree(view);
                 psFree(photView);
@@ -273,5 +273,5 @@
         psFree(psfs);
         if (!options->psf) {
-            psError(PS_ERR_UNKNOWN, false, "Unable to determine output PSF.");
+            psError(psErrorCodeLast(), false, "Unable to determine output PSF.");
             psFree(view);
             return false;
@@ -290,5 +290,5 @@
     // Zero point calibration
     if (!ppStackSourcesTransparency(options, view, config)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to calculate transparency differences");
+        psError(PPSTACK_ERR_DATA, false, "Unable to calculate transparency differences");
         psFree(view);
         return false;
Index: trunk/ppStack/src/ppStackReject.c
===================================================================
--- trunk/ppStack/src/ppStackReject.c	(revision 26928)
+++ trunk/ppStack/src/ppStackReject.c	(revision 27004)
@@ -61,5 +61,5 @@
     }
     if (!psThreadPoolWait(true)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to concatenate inspection lists.");
+        psError(psErrorCodeLast(), false, "Unable to concatenate inspection lists.");
         return false;
     }
@@ -172,5 +172,5 @@
 
     if (numRejected >= num - 1) {
-        psError(PS_ERR_UNKNOWN, true, "All inputs completely rejected; unable to proceed.");
+        psError(PPSTACK_ERR_REJECTED, true, "All inputs completely rejected; unable to proceed.");
         return false;
     }
Index: trunk/ppStack/src/ppStackSetup.c
===================================================================
--- trunk/ppStack/src/ppStackSetup.c	(revision 26928)
+++ trunk/ppStack/src/ppStackSetup.c	(revision 27004)
@@ -42,5 +42,5 @@
         options->statsFile = fopen(resolved, "w");
         if (!options->statsFile) {
-            psError(PS_ERR_IO, true, "Unable to open statistics file %s for writing.\n", resolved);
+            psError(PPSTACK_ERR_IO, true, "Unable to open statistics file %s for writing.\n", resolved);
             psFree(resolved);
             return false;
@@ -57,5 +57,5 @@
     }
     if (!tempDir) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, false, "Unable to find TEMP.DIR in site configuration");
+        psError(PPSTACK_ERR_CONFIG, false, "Unable to find TEMP.DIR in site configuration");
         return false;
     }
@@ -65,5 +65,5 @@
     const char *tempName = basename(outputName);
     if (!tempName) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, false, "Unable to construct basename for temporary files.");
+        psError(PPSTACK_ERR_ARGUMENTS, false, "Unable to construct basename for temporary files.");
         psFree(outputName);
         return false;
@@ -74,5 +74,5 @@
     const char *tempVariance = psMetadataLookupStr(NULL, recipe, "TEMP.VARIANCE"); // Suffix for var maps
     if (!tempImage || !tempMask || !tempVariance) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+        psError(PPSTACK_ERR_CONFIG, false,
                 "Unable to find TEMP.IMAGE, TEMP.MASK and TEMP.VARIANCE in recipe");
         psFree(outputName);
@@ -117,5 +117,5 @@
 
     if (!pmConfigMaskSetBits(NULL, NULL, config)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to determine mask value.");
+        psError(PPSTACK_ERR_CONFIG, false, "Unable to determine mask value.");
         return false;
     }
Index: trunk/ppStack/src/ppStackSources.c
===================================================================
--- trunk/ppStack/src/ppStackSources.c	(revision 26928)
+++ trunk/ppStack/src/ppStackSources.c	(revision 27004)
@@ -116,5 +116,5 @@
     psMetadata *airmassZP = psMetadataLookupMetadata(NULL, recipe, "ZP.AIRMASS"); // Airmass terms
     if (!airmassZP) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to find ZP.AIRMASS in recipe.");
+        psError(PPSTACK_ERR_CONFIG, false, "Unable to find ZP.AIRMASS in recipe.");
         return false;
     }
@@ -152,5 +152,5 @@
         if (!isfinite(exptime) || exptime == 0 || !isfinite(airmass) || airmass == 0 ||
             !expFilter || strlen(expFilter) == 0) {
-            psError(PS_ERR_UNEXPECTED_NULL, false,
+            psError(PPSTACK_ERR_CONFIG, false,
                     "Unable to find exposure time (%f), airmass (%f) or filter (%s)",
                     exptime, airmass, expFilter);
@@ -163,5 +163,5 @@
             airmassTerm = psMetadataLookupF32(NULL, airmassZP, filter);
             if (!isfinite(airmassTerm)) {
-                psError(PS_ERR_BAD_PARAMETER_VALUE, false,
+                psError(PPSTACK_ERR_CONFIG, false,
                         "Unable to find airmass term (ZP.AIRMASS) for filter %s", filter);
                 psFree(zp);
@@ -169,5 +169,5 @@
             }
         } else if (strcmp(filter, expFilter) != 0) {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false, "Filters don't match: %s vs %s", filter, expFilter);
+            psError(PPSTACK_ERR_CONFIG, false, "Filters don't match: %s vs %s", filter, expFilter);
             psFree(zp);
             return false;
@@ -182,5 +182,5 @@
     psArray *matches = pmSourceMatchSources(sourceLists, radius, true); // List of matches
     if (!matches) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to match sources");
+        psError(PPSTACK_ERR_DATA, false, "Unable to match sources");
         psFree(zp);
         return false;
@@ -196,5 +196,5 @@
                                                transIter, transRej, transThresh); // Transparencies per image
         if (!trans) {
-            psError(PS_ERR_UNKNOWN, false, "Unable to measure transparencies");
+            psError(PPSTACK_ERR_DATA, false, "Unable to measure transparencies");
             return false;
         }
@@ -241,5 +241,5 @@
             psArray *matches = pmSourceMatchSources(sourceLists, radius); // List of matches
             if (!matches) {
-                psError(PS_ERR_UNKNOWN, false, "Unable to match sources");
+                psError(PPSTACK_ERR_DATA, false, "Unable to match sources");
                 psFree(zp);
                 return false;
@@ -262,5 +262,5 @@
                                                   iter2, starRej2, starLimit); // Shifts for each image
         if (!offsets) {
-            psError(PS_ERR_UNKNOWN, false, "Unable to measure offsets");
+            psError(PPSTACK_ERR_DATA, false, "Unable to measure offsets");
             return false;
         }
Index: trunk/ppStack/src/ppStackThread.c
===================================================================
--- trunk/ppStack/src/ppStackThread.c	(revision 26928)
+++ trunk/ppStack/src/ppStackThread.c	(revision 27004)
@@ -102,5 +102,5 @@
             (FITS)->data[INDEX] = psFitsOpen(resolved, "r");                            \
             if (!(FITS)->data[INDEX]) { \
-                psError(PS_ERR_IO, false, "Unable to open file %s", (char*)(NAMES)->data[INDEX]); \
+                psError(PPSTACK_ERR_IO, false, "Unable to open file %s", (char*)(NAMES)->data[INDEX]); \
                 psFree(resolved); \
                 return NULL; \
@@ -152,10 +152,10 @@
     psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSTACK_RECIPE); // Recipe
     if (!recipe) {
-        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find recipe %s", PPSTACK_RECIPE);
+        psError(PPSTACK_ERR_CONFIG, false, "Unable to find recipe %s", PPSTACK_RECIPE);
         return NULL;
     }
     int rows = psMetadataLookupS32(NULL, recipe, "ROWS"); // Number of rows to read per chunk
     if (rows <= 0) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, false, "ROWS is not set in the recipe.");
+        psError(PPSTACK_ERR_CONFIG, false, "ROWS is not set in the recipe.");
         return NULL;
     }
@@ -204,5 +204,6 @@
                     keepReading = true;
                     if (!pmReadoutReadChunk(ro, imageFits, 0, NULL, rows, overlap, config)) {
-                        psError(PS_ERR_IO, false, "Unable to read chunk %d for file PPSTACK.INPUT %d",
+                        psError(PPSTACK_ERR_IO, false,
+                                "Unable to read chunk %d for file PPSTACK.INPUT %d",
                                 numChunk, i);
                         *status = false;
@@ -214,5 +215,6 @@
                     keepReading = true;
                     if (!pmReadoutReadChunkMask(ro, maskFits, 0, NULL, rows, overlap, config)) {
-                        psError(PS_ERR_IO, false, "Unable to read chunk %d for file PPSTACK.INPUT.MASK %d",
+                        psError(PPSTACK_ERR_IO, false,
+                                "Unable to read chunk %d for file PPSTACK.INPUT.MASK %d",
                                 numChunk, i);
                         *status = false;
@@ -224,5 +226,5 @@
                     keepReading = true;
                     if (!pmReadoutReadChunkVariance(ro, varianceFits, 0, NULL, rows, overlap, config)) {
-                        psError(PS_ERR_IO, false,
+                        psError(PPSTACK_ERR_IO, false,
                                 "Unable to read chunk %d for file PPSTACK.INPUT.VARIANCE %d",
                                 numChunk, i);
