Index: /trunk/psphot/src/psphot.c
===================================================================
--- /trunk/psphot/src/psphot.c	(revision 11262)
+++ /trunk/psphot/src/psphot.c	(revision 11263)
@@ -3,5 +3,5 @@
 static void usage (void) {
     fprintf (stderr, "USAGE: psphot [-file image(s)] [-list imagelist] (output)\n");
-    exit (2);
+    exit (PS_EXIT_CONFIG_ERROR);
 }
 
@@ -9,9 +9,6 @@
 
     psTimerStart ("complete");
-
     psphotErrorRegister();              // register our error codes/messages
-
-    // load implementation-specific models
-    psphotModelGroupInit ();
+    psphotModelGroupInit ();		// load implementation-specific models
 
     // load command-line arguments, options, and system config data
@@ -21,20 +18,21 @@
     // load input data (config and images (signal, noise, mask)
     if (!psphotParseCamera (config)) {
-        psErrorStackPrint(stderr, "error setting up the camera");
-        exit(1);
+        psErrorStackPrint(stderr, "Error setting up the camera");
+        exit (psphotGetExitStatus());
     }
-
-    // XXX for test checking of the config system
-    // psphotDumpConfig (config);
 
     // call psphot for each readout
     if (!psphotImageLoop (config)) {
-        psErrorStackPrint(stderr, " ");
-        exit(1);
+        psErrorStackPrint(stderr, "Error in the psphot image loop");
+        exit (psphotGetExitStatus());
     }
 
     psLogMsg ("psphot", 3, "complete psphot run: %f sec\n", psTimerMark ("complete"));
 
+    psErrorCode exit_status = psphotGetExitStatus();
     psphotCleanup (config);
-    exit (EXIT_SUCCESS);
+    exit (exit_status);
 }
+
+// all functions which return to this level must raise one of the top-level error codes if they
+// exit with an error.  these error codes are used to specify the program exit status
Index: /trunk/psphot/src/psphot.h
===================================================================
--- /trunk/psphot/src/psphot.h	(revision 11262)
+++ /trunk/psphot/src/psphot.h	(revision 11263)
@@ -99,2 +99,3 @@
 bool psphotMergeSources (psArray *oldSources, psArray *newSources);
 bool psphotLoadExtSources (pmConfig *config, pmFPAview *view, psArray *sources);
+psExit psphotGetExitStatus ();
Index: /trunk/psphot/src/psphotBlendFit.c
===================================================================
--- /trunk/psphot/src/psphotBlendFit.c	(revision 11262)
+++ /trunk/psphot/src/psphotBlendFit.c	(revision 11263)
@@ -91,4 +91,4 @@
 
     psLogMsg ("psphot.psphotBlendFit", PS_LOG_INFO, "fit models: %f sec for %d objects (%d psf, %d ext, %d failed, %ld skipped)\n", psTimerMark ("psphot"), Nfit, Npsf, Next, Nfail, sources->n - Nfit);
-    return (true);
+    return true;
 }
Index: /trunk/psphot/src/psphotChoosePSF.c
===================================================================
--- /trunk/psphot/src/psphotChoosePSF.c	(revision 11262)
+++ /trunk/psphot/src/psphotChoosePSF.c	(revision 11263)
@@ -256,4 +256,5 @@
 }
 
+// measure average parameters of the PSF model
 bool psphotPSFstats (pmReadout *readout, psMetadata *recipe, pmPSF *psf) {
 
@@ -295,8 +296,9 @@
     psF64 FWHM_Y = FWHM_X * (axes.minor / axes.major);
 
-    psMetadataAdd (recipe, PS_LIST_TAIL, "FWHM_X", PS_DATA_F32 | PS_META_REPLACE, "PSF FWHM Major axis", FWHM_X);
-    psMetadataAdd (recipe, PS_LIST_TAIL, "FWHM_Y", PS_DATA_F32 | PS_META_REPLACE, "PSF FWHM Minor axis", FWHM_Y);
-    psMetadataAdd (recipe, PS_LIST_TAIL, "ANGLE",  PS_DATA_F32 | PS_META_REPLACE, "PSF angle",           axes.theta);
-    psMetadataAdd (recipe, PS_LIST_TAIL, "NPSFSTAR", PS_DATA_S32 | PS_META_REPLACE, "number of stars used to make PSF", psf->nPSFstars);
+    psMetadataAddF32 (recipe, PS_LIST_TAIL, "FWHM_X", 	PS_META_REPLACE, "PSF FWHM Major axis", FWHM_X);
+    psMetadataAddF32 (recipe, PS_LIST_TAIL, "FWHM_Y", 	PS_META_REPLACE, "PSF FWHM Minor axis", FWHM_Y);
+    psMetadataAddF32 (recipe, PS_LIST_TAIL, "ANGLE",  	PS_META_REPLACE, "PSF angle",           axes.theta);
+    psMetadataAddS32 (recipe, PS_LIST_TAIL, "NPSFSTAR", PS_META_REPLACE, "Number of stars used to make PSF", psf->nPSFstars);
+    psMetadataAddBool(recipe, PS_LIST_TAIL, "PSFMODEL", PS_META_REPLACE, "Valid PSF Model?", true);
 
     psFree (modelEXT);
@@ -306,5 +308,5 @@
 }
 
-// XXX fix this wrt re-definition of PM_PAR_SXX
+// determine approximate PSF shape parameters based on the moments
 bool psphotMomentsStats (pmReadout *readout, psMetadata *recipe, psArray *sources) {
 
@@ -347,7 +349,9 @@
     FWHM_T /= FWHM_N;
 
-    psMetadataAdd (recipe, PS_LIST_TAIL, "FWHM_X", PS_DATA_F32 | PS_META_REPLACE, "PSF FWHM Major axis", FWHM_X);
-    psMetadataAdd (recipe, PS_LIST_TAIL, "FWHM_Y", PS_DATA_F32 | PS_META_REPLACE, "PSF FWHM Minor axis", FWHM_Y);
-    psMetadataAdd (recipe, PS_LIST_TAIL, "ANGLE",  PS_DATA_F32 | PS_META_REPLACE, "PSF angle",           FWHM_T);
+    psMetadataAddF32 (recipe, PS_LIST_TAIL, "FWHM_X",   PS_META_REPLACE, "PSF FWHM Major axis (from moments)", FWHM_X);
+    psMetadataAddF32 (recipe, PS_LIST_TAIL, "FWHM_Y",   PS_META_REPLACE, "PSF FWHM Minor axis (from moments)", FWHM_Y);
+    psMetadataAddF32 (recipe, PS_LIST_TAIL, "ANGLE",    PS_META_REPLACE, "PSF angle",           FWHM_T);
+    psMetadataAddS32 (recipe, PS_LIST_TAIL, "NPSFSTAR", PS_META_REPLACE, "Number of stars used to make PSF", 0);
+    psMetadataAddBool(recipe, PS_LIST_TAIL, "PSFMODEL", PS_META_REPLACE, "Valid PSF Model?", false);
 
     return true;
Index: /trunk/psphot/src/psphotCleanup.c
===================================================================
--- /trunk/psphot/src/psphotCleanup.c	(revision 11262)
+++ /trunk/psphot/src/psphotCleanup.c	(revision 11263)
@@ -15,2 +15,20 @@
     return;
 }
+
+psExit psphotGetExitStatus () {
+
+    psErrorCode err = psErrorCodeLast ();
+    switch (err) {
+      case PSPHOT_ERR_SYS:
+	return PS_EXIT_SYS_ERROR;
+      case PSPHOT_ERR_CONFIG:
+	return PS_EXIT_CONFIG_ERROR;
+      case PSPHOT_ERR_PROG:
+	return PS_EXIT_PROG_ERROR;
+      case PSPHOT_ERR_DATA:
+	return PS_EXIT_DATA_ERROR;
+      default:
+	return PS_EXIT_UNKNOWN_ERROR;
+    }	
+    return PS_EXIT_UNKNOWN_ERROR;
+}
Index: /trunk/psphot/src/psphotErrorCodes.dat
===================================================================
--- /trunk/psphot/src/psphotErrorCodes.dat	(revision 11262)
+++ /trunk/psphot/src/psphotErrorCodes.dat	(revision 11263)
@@ -2,9 +2,7 @@
 # This file is used to generate psphotErrorClasses.h
 #
-BASE = 512		First value we use; lower values belong to psLib
+BASE = 200		First value we use; lower values belong to psLib
 UNKNOWN			Unknown PM error code
 NOT_IMPLEMENTED		Desired feature is not yet implemented
-ARGUMENTS		Incorrect arguments
-CONFIG			Problem in configure files
 FITS			Problem in FITS I/O
 FITS_WCS		Error interpreting FITS WCS information
@@ -13,2 +11,8 @@
 APERTURE		Problem with aperture photometry
 SKY			Problem in sky determination
+# these errors correspond to standard exit conditions
+ARGUMENTS               Incorrect arguments
+SYS                     System error
+CONFIG                  Problem in configure files
+PROG                    Programming error
+DATA                    invalid data
Index: /trunk/psphot/src/psphotFindPeaks.c
===================================================================
--- /trunk/psphot/src/psphotFindPeaks.c	(revision 11262)
+++ /trunk/psphot/src/psphotFindPeaks.c	(revision 11263)
@@ -17,5 +17,8 @@
 	float FWHM_X = psMetadataLookupF32 (&status_x, recipe, "FWHM_X");
 	float FWHM_Y = psMetadataLookupF32 (&status_y, recipe, "FWHM_Y");
-	if (!status_x | !status_y) psAbort ("psphotFindPeaks", "FWHM_X or FWHM_Y not defined");
+	if (!status_x | !status_y) {
+	    psError(PSPHOT_ERR_CONFIG, false, "FWHM_X or FWHM_Y not defined");
+	    return false;
+	}
 	SIGMA_SMTH  = 0.5*(FWHM_X + FWHM_Y) / (2.0*sqrt(2.0*log(2.0)));
 	NSIGMA_SMTH = psMetadataLookupF32 (&status, recipe, "PEAKS_SMOOTH_NSIGMA");
@@ -83,5 +86,11 @@
     // find the peaks in the smoothed image
     psArray *peaks = pmFindImagePeaks (smooth_im, threshold);
-    if (peaks == NULL) psAbort ("find peaks", "no peaks found");
+    if (peaks == NULL) {
+	// XXX this may also be due to a programming or config error
+	// XXX do we need to set something in the readout->analysis to indicate that 
+	// we tried and failed to find peaks (something in the header data)
+	psError(PSPHOT_ERR_DATA, false, "no peaks found in this image");
+	return false;
+    }
     
     // correct the peak values to S/N = sqrt(value*effArea)
Index: /trunk/psphot/src/psphotImageLoop.c
===================================================================
--- /trunk/psphot/src/psphotImageLoop.c	(revision 11262)
+++ /trunk/psphot/src/psphotImageLoop.c	(revision 11263)
@@ -1,5 +1,6 @@
 # include "psphot.h"
 
-// XXX where do we load optional mask and weight input images?
+// XXX the errors in the pmFPAfileIOChecks could also be due to a programming or config error
+// XXX we need to either handle those errors or handle the error in pmFPAfileIOChecks and exit
 bool psphotImageLoop (pmConfig *config) {
 
@@ -11,5 +12,5 @@
     pmFPAfile *input = psMetadataLookupPtr (&status, config->files, "PSPHOT.INPUT");
     if (!status) {
-	psError(PS_ERR_IO, false, "Can't find input data!");
+	psError(PSPHOT_ERR_PROG, false, "Can't find input data!");
 	return false;
     }
@@ -19,5 +20,5 @@
     // files associated with the science image
     if (!pmFPAfileIOChecks (config, view, PM_FPA_BEFORE)) {
-	psError(PS_ERR_UNKNOWN, false, "failed IO for fpa in psphot\n");
+	psError(PSPHOT_ERR_DATA, false, "failed IO for fpa in psphot\n");
 	psFree(view);
 	return false;
@@ -28,5 +29,5 @@
         if (! chip->process || ! chip->file_exists) { continue; }
 	if (!pmFPAfileIOChecks (config, view, PM_FPA_BEFORE)) {
-            psError(PS_ERR_UNKNOWN, false, "failed IO for chip %d in psphot\n", view->chip);
+            psError(PSPHOT_ERR_DATA, false, "failed IO for chip %d in psphot\n", view->chip);
 	    psFree (view);
 	    return false;
@@ -37,5 +38,5 @@
             if (! cell->process || ! cell->file_exists) { continue; }
 	    if (!pmFPAfileIOChecks (config, view, PM_FPA_BEFORE)) {
-		psError(PS_ERR_UNKNOWN, false, "failed IO for chip %d, cell %d in psphot\n", view->chip, view->cell);
+		psError(PSPHOT_ERR_DATA, false, "failed IO for chip %d, cell %d in psphot\n", view->chip, view->cell);
 		psFree (view);
 		return false;
@@ -45,5 +46,5 @@
 	    while ((readout = pmFPAviewNextReadout (view, input->fpa, 1)) != NULL) {
 		if (!pmFPAfileIOChecks (config, view, PM_FPA_BEFORE)) {
-		    psError(PS_ERR_UNKNOWN, false, "failed IO for chip %d, cell %d, readout %d in psphot\n", view->chip, view->cell, view->readout);
+		    psError(PSPHOT_ERR_DATA, false, "failed IO for chip %d, cell %d, readout %d in psphot\n", view->chip, view->cell, view->readout);
 		    psFree (view);
 		    return false;
@@ -54,5 +55,5 @@
 		// run the actual photometry analysis
 		if (!psphotReadout (config, view)) {
-		    psError(PS_ERR_UNKNOWN, false, "failed psphotReadout for chip %d, cell %d, readout %d\n", view->chip, view->cell, view->readout);
+		    psError(psErrorCodeLast(), false, "failure in psphotReadout for chip %d, cell %d, readout %d\n", view->chip, view->cell, view->readout);
 		    psFree (view);
 		    return false;
@@ -60,5 +61,5 @@
 
 		if (!pmFPAfileIOChecks (config, view, PM_FPA_AFTER)) {
-		    psError(PS_ERR_UNKNOWN, false, "failed IO for chip %d, cell %d, readout %d in psphot\n", view->chip, view->cell, view->readout);
+		    psError(PSPHOT_ERR_DATA, false, "failed IO for chip %d, cell %d, readout %d in psphot\n", view->chip, view->cell, view->readout);
 		    psFree (view);
 		    return false;
@@ -66,5 +67,5 @@
 	    }
 	    if (!pmFPAfileIOChecks (config, view, PM_FPA_AFTER)) {
-		psError(PS_ERR_UNKNOWN, false, "failed IO for chip %d, cell %d in psphot\n", view->chip, view->cell);
+		psError(PSPHOT_ERR_DATA, false, "failed IO for chip %d, cell %d in psphot\n", view->chip, view->cell);
 		psFree (view);
 		return false;
@@ -72,5 +73,5 @@
 	}
 	if (!pmFPAfileIOChecks (config, view, PM_FPA_AFTER)) {
-            psError(PS_ERR_UNKNOWN, false, "failed IO for chip %d in psphot\n", view->chip);
+            psError(PSPHOT_ERR_DATA, false, "failed IO for chip %d in psphot\n", view->chip);
 	    psFree (view);
 	    return false;
@@ -78,5 +79,5 @@
     }
     if (!pmFPAfileIOChecks (config, view, PM_FPA_AFTER)) {
-	psError(PS_ERR_UNKNOWN, false, "failed IO for fpa in psphot\n");
+	psError(PSPHOT_ERR_DATA, false, "failed IO for fpa in psphot\n");
 	psFree (view);
 	return false;
Index: /trunk/psphot/src/psphotImageMedian.c
===================================================================
--- /trunk/psphot/src/psphotImageMedian.c	(revision 11262)
+++ /trunk/psphot/src/psphotImageMedian.c	(revision 11263)
@@ -99,6 +99,8 @@
 	    pmFPAfileCopyStructureView (file->fpa, inFPA, DX, DY, view);
 	    model = pmFPAviewThisReadout (view, file->fpa);
-	    if (nx != model->image->numCols) psAbort ("psphot", "inconsistent size");
-	    if (ny != model->image->numRows) psAbort ("psphot", "inconsistent size");
+	    if ((nx != model->image->numCols) || (ny != model->image->numRows)) {
+		psError (PSPHOT_ERR_PROG, true, "inconsistent sizes for model dimensions");
+		return false;
+	    }
 	}
     }
@@ -230,6 +232,8 @@
 	    pmFPAfileCopyStructureView (file->fpa, inFPA, 1, 1, view);
 	    background = pmFPAviewThisReadout (view, file->fpa);
-	    if (Nx != background->image->numCols) psAbort ("psphot", "inconsistent size");
-	    if (Ny != background->image->numRows) psAbort ("psphot", "inconsistent size");
+	    if ((Nx != background->image->numCols) || (Ny != background->image->numRows)) {
+		psError (PSPHOT_ERR_PROG, true, "inconsistent sizes for background dimensions");
+		return false;
+	    }
 	}
     } else {
Index: /trunk/psphot/src/psphotMergeSources.c
===================================================================
--- /trunk/psphot/src/psphotMergeSources.c	(revision 11262)
+++ /trunk/psphot/src/psphotMergeSources.c	(revision 11263)
@@ -16,5 +16,5 @@
 
     // find the currently selected readout
-    pmReadout  *readout = pmFPAfileThisReadout (config->files, view, "INPUT.SRC");
+    pmReadout  *readout = pmFPAfileThisReadout (config->files, view, "PSPHOT.SRC");
     if (!readout) {
 	psLogMsg ("psphot", 3, "no external sources supplied");
Index: /trunk/psphot/src/psphotParseCamera.c
===================================================================
--- /trunk/psphot/src/psphotParseCamera.c	(revision 11262)
+++ /trunk/psphot/src/psphotParseCamera.c	(revision 11263)
@@ -13,4 +13,13 @@
     }
 
+    // if we have requested PSPHOT.SRC, attempt to resolve it 
+    if (psMetadataLookupPtr(NULL, config->arguments, "SRC")) { 
+	pmFPAfileDefineFromArgs (&status, config, "PSPHOT.SRC", "SRC");
+	if (!status) {
+	    psError(PSPHOT_ERR_CONFIG, false, "Failed to find/build PSPHOT.SRC");
+	    return status;
+	}
+    }
+
     // select recipe options supplied on command line
     psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
@@ -18,13 +27,9 @@
     // if MASK or WEIGHT was supplied on command line, bind files to input fpa
     // XXX these do not quite yet work: pmFPAAddSourceFromHeader is not appropriate
-    pmFPAfileBindFromArgs (NULL, input, config, "INPUT.MASK", "MASK");
-    pmFPAfileBindFromArgs (NULL, input, config, "INPUT.WEIGHT", "WEIGHT");
+    pmFPAfileBindFromArgs (NULL, input, config, "PSPHOT.MASK", "MASK");
+    pmFPAfileBindFromArgs (NULL, input, config, "PSPHOT.WEIGHT", "WEIGHT");
 
     // optionally load the PSF Model and/or fixed stars
-    pmFPAfileBindFromArgs (NULL, input, config, "INPUT.PSF", "PSF");
-    pmFPAfile *srcInput = pmFPAfileDefineFromArgs (NULL, config, "INPUT.SRC", "SRC");
-    if (!srcInput) {
-	fprintf (stderr, "!");
-    }
+    pmFPAfileBindFromArgs (NULL, input, config, "PSPHOT.PSF", "PSF");
 
     // set default recipe values here
@@ -47,5 +52,5 @@
     if (!status || saveOutput) {
 	if (!pmFPAfileDefineOutput (config, input->fpa, "PSPHOT.OUTPUT")) {
-	    psError(PS_ERR_IO, false, "Cannot find a rule for PSPHOT.OUTPUT");
+	    psError(PSPHOT_ERR_CONFIG, false, "Cannot find a rule for PSPHOT.OUTPUT");
 	    return false;
 	}
@@ -55,5 +60,5 @@
     if (psMetadataLookupBool(NULL, recipe, "SAVE.RESID")) {
 	if (!pmFPAfileDefineOutput (config, input->fpa, "PSPHOT.RESID")) {
-	    psError(PS_ERR_IO, false, "Cannot find a rule for PSPHOT.BACKMDL");
+	    psError(PSPHOT_ERR_CONFIG, false, "Cannot find a rule for PSPHOT.BACKMDL");
 	    return false;
 	}
@@ -68,5 +73,5 @@
     if (psMetadataLookupBool(NULL, recipe, "SAVE.BACKMDL")) {
 	if (!pmFPAfileDefineFromFPA (config, input->fpa, DX, DY, "PSPHOT.BACKMDL")) {
-	    psError(PS_ERR_IO, false, "Cannot find a rule for PSPHOT.BACKMDL");
+	    psError(PSPHOT_ERR_CONFIG, false, "Cannot find a rule for PSPHOT.BACKMDL");
 	    return false;
 	}
@@ -75,5 +80,5 @@
     if (psMetadataLookupBool(NULL, recipe, "SAVE.BACKGND")) {
 	if (!pmFPAfileDefineFromFPA (config, input->fpa,  1,  1, "PSPHOT.BACKGND")) {
-	    psError(PS_ERR_IO, false, "Cannot find a rule for PSPHOT.BACKGND");
+	    psError(PSPHOT_ERR_CONFIG, false, "Cannot find a rule for PSPHOT.BACKGND");
 	    return false;
 	}
@@ -82,5 +87,5 @@
     if (psMetadataLookupBool(NULL, recipe, "SAVE.BACKSUB")) {
 	if (!pmFPAfileDefineFromFPA (config, input->fpa,  1,  1, "PSPHOT.BACKSUB")) {
-	    psError(PS_ERR_IO, false, "Cannot find a rule for PSPHOT.");
+	    psError(PSPHOT_ERR_CONFIG, false, "Cannot find a rule for PSPHOT.");
 	    return false;
 	}
@@ -89,5 +94,5 @@
     if (psMetadataLookupBool(NULL, recipe, "SAVE.PSF")) {
 	if (!pmFPAfileDefineOutput (config, input->fpa, "PSPHOT.PSF.SAVE")) {
-	    psError(PS_ERR_IO, false, "Cannot find a rule for PSPHOT.PSF.SAVE");
+	    psError(PSPHOT_ERR_CONFIG, false, "Cannot find a rule for PSPHOT.PSF.SAVE");
 	    return false;
 	}
@@ -115,5 +120,5 @@
 	    int chipNum = atoi(chips->data[i]);
 	    if (! pmFPASelectChip(input->fpa, chipNum, false)) {
-		psError(PS_ERR_IO, false, "Chip number %d doesn't exist in camera.\n", chipNum);
+		psError(PSPHOT_ERR_CONFIG, false, "Chip number %d doesn't exist in camera.\n", chipNum);
 		return false;
 	    }
@@ -121,9 +126,7 @@
     }
     psFree (chips);
-
     psTrace("psphot", 1, "Done with psphotParseCamera...\n");
 
     psErrorClear();			// some metadata lookup may have failed
-
     return true;
 }
Index: /trunk/psphot/src/psphotReadout.c
===================================================================
--- /trunk/psphot/src/psphotReadout.c	(revision 11262)
+++ /trunk/psphot/src/psphotReadout.c	(revision 11263)
@@ -5,13 +5,20 @@
     // select the current recipe
     psMetadata *recipe  = psMetadataLookupPtr (NULL, config->recipes, PSPHOT_RECIPE);
+    if (!recipe) {
+        psError(PSPHOT_ERR_CONFIG, false, "missing recipe %s", PSPHOT_RECIPE);
+        return false;
+    }
 
     // find the currently selected readout
     pmReadout  *readout = pmFPAfileThisReadout (config->files, view, "PSPHOT.INPUT");
+    PS_ASSERT_PTR_NON_NULL (readout, false);
 
     // optional break-point for processing
     char *breakPt = psMetadataLookupStr (NULL, recipe, "BREAK_POINT");
+    PS_ASSERT_PTR_NON_NULL (breakPt, false);
 
     // generate mask & weight images if they don't already exit
     if (!pmReadoutGenerateMaskWeight (readout, true)) {
+        psError (PSPHOT_ERR_CONFIG, false, "trouble creating mask and/or weight");
         return false;
     }
@@ -34,5 +41,7 @@
 
     // generate a background model (median, smoothed image)
-    psphotImageMedian (config, view);
+    if (!psphotImageMedian (config, view)) {
+        return psphotReadoutCleanup (config, readout, recipe, NULL, NULL);
+    }
 
     if (!strcasecmp (breakPt, "BACKMDL")) {
@@ -40,12 +49,14 @@
     }
 
-    pmReadout *background = psphotSelectBackground (config, view);
-
     // find the peaks in the image
     psArray *peaks = psphotFindPeaks (readout, recipe, 1);
+    if (!peaks) {
+	psLogMsg ("psphot", 3, "unable to find peaks in this image");
+	return psphotReadoutCleanup (config, readout, recipe, NULL, NULL);
+    }
 
     // construct sources and measure basic stats
-    // limit moments analysis by S/N?
     psArray *sources = psphotSourceStats (readout, recipe, peaks);
+    if (!sources) return false;
     psFree (peaks);
 
@@ -55,13 +66,13 @@
 
     // mark blended peaks PS_SOURCE_BLEND
-    psphotBasicDeblend (sources, recipe);
+    if (!psphotBasicDeblend (sources, recipe)) {
+	psLogMsg ("psphot", 3, "failed on deblend analysis");
+	return psphotReadoutCleanup (config, readout, recipe, NULL, sources);
+    }
 
     // classify sources based on moments, brightness
     if (!psphotRoughClass (sources, recipe)) {
-        psFree (sources);
-        psLogMsg ("psphot", 3, "failed to find a valid PSF clump for image");
-        pmFPAfileDropInternal (config->files, "PSPHOT.BACKMDL");
-        pmFPAfileDropInternal (config->files, "PSPHOT.BACKGND");
-        return false;
+	psLogMsg ("psphot", 3, "failed to find a valid PSF clump for image");
+	return psphotReadoutCleanup (config, readout, recipe, NULL, sources);
     }
     if (!strcasecmp (breakPt, "MOMENTS")) {
@@ -72,9 +83,9 @@
     pmPSF *psf = psphotChoosePSF (readout, sources, recipe);
     if (psf == NULL) {
-        psError(PSPHOT_ERR_UNKNOWN, false, "failure to construct a psf model");
-        return false;
+	psLogMsg ("psphot", 3, "failure to construct a psf model");
+	return psphotReadoutCleanup (config, readout, recipe, psf, sources);
     }
     if (!strcasecmp (breakPt, "PSFMODEL")) {
-        return psphotReadoutCleanup(config, readout, recipe, psf, sources);
+        return psphotReadoutCleanup (config, readout, recipe, psf, sources);
     }
 
@@ -142,4 +153,6 @@
 
     // calculate source magnitudes
+    // XXX modify this API to take config, view?
+    pmReadout *background = psphotSelectBackground (config, view);
     psphotMagnitudes(sources, recipe, psf, background);
 
Index: /trunk/psphot/src/psphotReadoutCleanup.c
===================================================================
--- /trunk/psphot/src/psphotReadoutCleanup.c	(revision 11262)
+++ /trunk/psphot/src/psphotReadoutCleanup.c	(revision 11263)
@@ -1,15 +1,26 @@
 # include "psphot.h"
 
+// psphotReadoutCleanup is called on exit from psphotReadout if the last raised
+// error is not a DATA error, then there was a serious problem.  only in this
+// case, or if the fail on the stats measurement, do we return false
 bool psphotReadoutCleanup (pmConfig *config, pmReadout *readout, psMetadata *recipe, pmPSF *psf, psArray *sources) {
+
+    psErrorCode err = psErrorCodeLast();
+    if (err != PSPHOT_ERR_DATA) {
+	return false;
+    }
 
     // use the psf-model to measure FWHM stats
     if (psf) {
+	// don't call psphotPSFstats unless we have a valid pdf
+	// if it fails, there is probably a programming error 
         if (!psphotPSFstats (readout, recipe, psf)) {
-            psError(PS_ERR_IO, true, "Failed to measure PSF shape parameters");
+            psError(PSPHOT_ERR_PROG, false, "Failed to measure PSF shape parameters");
             return false;
         }
-    } else if (sources) {
+    }
+    if (!psf && sources) {
         if (!psphotMomentsStats (readout, recipe, sources)) {
-            psError(PS_ERR_IO, true, "Failed to measure Moment shape parameters");
+            psError(PSPHOT_ERR_PROG, false, "Failed to measure Moment shape parameters");
             return false;
         }
Index: /trunk/psphot/src/psphotRoughClass.c
===================================================================
--- /trunk/psphot/src/psphotRoughClass.c	(revision 11262)
+++ /trunk/psphot/src/psphotRoughClass.c	(revision 11263)
@@ -9,15 +9,20 @@
 
     psfClump = pmSourcePSFClump (sources, recipe);
+    if (psfClump.X < 0) {
+	psError(PSPHOT_ERR_PROG, false, "programming error calling pmSourcePSFClump");
+	return false;
+    }
+    if (!psfClump.X || !psfClump.Y) {
+	psError(PSPHOT_ERR_DATA, true, "Failed to find a valid PSF clump");
+	return false;
+    }
     psLogMsg ("psphot", 3, "psf clump  X,  Y: %f, %f\n", psfClump.X, psfClump.Y);
     psLogMsg ("psphot", 3, "psf clump DX, DY: %f, %f\n", psfClump.dX, psfClump.dY);
 
-    // did we find a valid psfClump?
-    if (!psfClump.X || !psfClump.Y) {
-	psError(PSPHOT_ERR_PSF, true, "Failed to find a valid PSF clump");
+    // group into STAR, COSMIC, EXTENDED, SATURATED, etc.
+    if (!pmSourceRoughClass (sources, recipe, psfClump)) {
+	psError(PSPHOT_ERR_PROG, false, "programming error calling pmSourceRoughClass");
 	return false;
     }
-
-    // group into STAR, COSMIC, EXTENDED, SATURATED, etc.
-    pmSourceRoughClass (sources, recipe, psfClump);
 
     // optional printout of source moments only
Index: /trunk/psphot/src/psphotSourceStats.c
===================================================================
--- /trunk/psphot/src/psphotSourceStats.c	(revision 11262)
+++ /trunk/psphot/src/psphotSourceStats.c	(revision 11263)
@@ -11,8 +11,13 @@
     // determine properties (sky, moments) of initial sources
     float INNER    = psMetadataLookupF32 (&status, recipe, "SKY_INNER_RADIUS");
+    if (!status) return NULL;
     float OUTER    = psMetadataLookupF32 (&status, recipe, "SKY_OUTER_RADIUS");
+    if (!status) return NULL;
     float RADIUS   = psMetadataLookupF32 (&status, recipe, "PSF_MOMENTS_RADIUS");
+    if (!status) return NULL;
     float MIN_SN   = psMetadataLookupF32 (&status, recipe, "MOMENTS_SN_MIN");
+    if (!status) return NULL;
     char *breakPt  = psMetadataLookupStr (&status, recipe, "BREAK_POINT");
+    if (!status) return NULL;
 
     sources = psArrayAllocEmpty (peaks->n);
