Index: trunk/psLib/src/imageops/psImageConvolve.c
===================================================================
--- trunk/psLib/src/imageops/psImageConvolve.c	(revision 33083)
+++ trunk/psLib/src/imageops/psImageConvolve.c	(revision 33089)
@@ -1039,5 +1039,5 @@
             }
         }
-        if (!psThreadPoolWait(true)) {
+        if (!psThreadPoolWait(true, true)) {
             psError(PS_ERR_UNKNOWN, false, "Error waiting for threads.");
             psFree(gaussNorm);
@@ -1390,5 +1390,5 @@
               }
               // wait here for the threaded jobs to finish (NOP if threading is not active)
-              if (!psThreadPoolWait(true)) {
+              if (!psThreadPoolWait(true, true)) {
                   psError(PS_ERR_UNKNOWN, false, "Unable to smooth image");
                   psFree(calculation);
@@ -1437,5 +1437,5 @@
 
               // wait here for the threaded jobs to finish (NOP if threading is not active)
-              if (!psThreadPoolWait(true)) {
+              if (!psThreadPoolWait(true, true)) {
                   psError(PS_ERR_UNKNOWN, false, "Unable to smooth image");
                   psFree(calculation);
@@ -1752,5 +1752,5 @@
             }
         }
-        if (!psThreadPoolWait(true)) {
+        if (!psThreadPoolWait(true, true)) {
             psError(PS_ERR_UNKNOWN, false, "Error waiting for threads.");
             psFree(conv);
@@ -1787,5 +1787,5 @@
             }
         }
-        if (!psThreadPoolWait(true)) {
+        if (!psThreadPoolWait(true, true)) {
             psError(PS_ERR_UNKNOWN, false, "Error waiting for threads.");
             psFree(conv);
Index: trunk/psLib/src/imageops/psImageCovariance.c
===================================================================
--- trunk/psLib/src/imageops/psImageCovariance.c	(revision 33083)
+++ trunk/psLib/src/imageops/psImageCovariance.c	(revision 33089)
@@ -193,5 +193,5 @@
     }
 
-    if (threaded && !psThreadPoolWait(true)) {
+    if (threaded && !psThreadPoolWait(true, true)) {
         psError(PS_ERR_UNKNOWN, false, "Error waiting for threads.");
         return false;
@@ -360,5 +360,5 @@
         }
     }
-    if (threaded && !psThreadPoolWait(true)) {
+    if (threaded && !psThreadPoolWait(true, true)) {
         psError(PS_ERR_UNKNOWN, false, "Error waiting for threads.");
         return false;
Index: trunk/psLib/src/sys/psThread.c
===================================================================
--- trunk/psLib/src/sys/psThread.c	(revision 33083)
+++ trunk/psLib/src/sys/psThread.c	(revision 33089)
@@ -179,4 +179,6 @@
     PS_ASSERT_THREAD_TASK_NON_NULL(task, false);
 
+    // fprintf(stderr, "adding task %s\n", task->type);
+
     if (!tasks) {
         tasks = psHashAlloc(TASK_BUCKETS);
@@ -189,4 +191,5 @@
 {
     PS_ASSERT_STRING_NON_EMPTY(type, false);
+    // fprintf(stderr, "removing task %s\n", type);
 
     return psHashRemove(tasks, type);
@@ -223,4 +226,5 @@
 
         psThreadTask *task = psHashLookup(tasks, job->type); // Task to execute job
+        // fprintf(stderr, "launching job %s\n", job->type);
 #ifdef HAVE_BACKTRACE
         if (!task && bt_buffer) {
@@ -246,5 +250,10 @@
                  "invalid number of arguments to %s (%ld supplied, expected %d)",
                  task->type, job->args->n, task->nArgs);
+        // fprintf(stderr, "    thread for %s %p launching on %p\n", job->type, task->function, self);
+
+        // Run the job's function
         bool status = task->function(job); // Status of executing task
+
+        // fprintf(stderr, "    thread for %s %p finished on %p with status %d\n", job->type, task->function, self, status);
 
         // Put the completed job on the 'done' queue
@@ -306,6 +315,7 @@
 
 // call this function after you have added jobs to the queue and
-bool psThreadPoolWait(bool harvest)
-{
+bool psThreadPoolWait(bool harvest, bool harvestOnFailure)
+{
+    // fprintf(stderr, "psThreadPoolWait called with harvest: %d\n", harvest);
     if (!pool || pool->n == 0) {
         // No threads initialised, so everything's done
@@ -326,4 +336,6 @@
 #endif
 
+    // accumulate the number of faulted jobs that we encounter
+    int numFaults = 0;
     while (1) {
         // check for an error
@@ -331,5 +343,5 @@
             psThread *thread = pool->data[i];
             if (thread->fault) {
-                return false;
+                numFaults++;
             }
         }
@@ -354,9 +366,9 @@
             // Nothing in the queue and nothing more to add
             // Ensure everything is harvested, if requested
-            if (harvest) {
+            if (harvest || (numFaults && harvestOnFailure)) {
                 psThreadJobHarvest();
             }
             psThreadUnlock();
-            return true;
+            return numFaults == 0;
         }
 
Index: trunk/psLib/src/sys/psThread.h
===================================================================
--- trunk/psLib/src/sys/psThread.h	(revision 33083)
+++ trunk/psLib/src/sys/psThread.h	(revision 33089)
@@ -116,7 +116,9 @@
 /// Wait for the thread pool to finish
 ///
-/// This function blocks (waits in usleep) until either an error is detected on one of the threads or until ll
-/// threads are idle and no jobs are left on the queue
-bool psThreadPoolWait(bool harvest      // Harvest the jobs from the queue?
+/// This function blocks (waits in usleep) until all  threads are idle and no jobs
+/// are left on the queue
+/// returns success if all jobs return success, otherwise returns false
+bool psThreadPoolWait(bool harvest,         // Harvest the jobs from the queue?
+                      bool harvestOnFailure // If harvest is false, harvest the jobs if a failure is encountered
     );
 
Index: trunk/psModules/src/camera/pmReadoutFake.c
===================================================================
--- trunk/psModules/src/camera/pmReadoutFake.c	(revision 33083)
+++ trunk/psModules/src/camera/pmReadoutFake.c	(revision 33089)
@@ -314,5 +314,5 @@
                 }
             }
-            if (!psThreadPoolWait(true)) {
+            if (!psThreadPoolWait(true, true)) {
                 psError(PS_ERR_UNKNOWN, false, "Error waiting for threads.");
                 psFree(groups);
Index: trunk/psModules/src/detrend/pmBias.c
===================================================================
--- trunk/psModules/src/detrend/pmBias.c	(revision 33083)
+++ trunk/psModules/src/detrend/pmBias.c	(revision 33089)
@@ -154,5 +154,5 @@
     if (threaded) {
         // wait here for the threaded jobs to finish
-        if (!psThreadPoolWait(true)) {
+        if (!psThreadPoolWait(true, true)) {
             psError(PS_ERR_UNKNOWN, false, "Unable to apply bias correction.");
             return false;
Index: trunk/psModules/src/detrend/pmDark.c
===================================================================
--- trunk/psModules/src/detrend/pmDark.c	(revision 33083)
+++ trunk/psModules/src/detrend/pmDark.c	(revision 33089)
@@ -601,5 +601,5 @@
     if (threaded) {
         // wait here for the threaded jobs to finish
-        if (!psThreadPoolWait(true)) {
+        if (!psThreadPoolWait(true, true)) {
             psError(PS_ERR_UNKNOWN, false, "Unable to apply dark.");
             psFree(orders);
Index: trunk/psModules/src/detrend/pmFlatField.c
===================================================================
--- trunk/psModules/src/detrend/pmFlatField.c	(revision 33083)
+++ trunk/psModules/src/detrend/pmFlatField.c	(revision 33089)
@@ -161,5 +161,5 @@
     if (threaded) {
         // wait here for the threaded jobs to finish
-        if (!psThreadPoolWait(true)) {
+        if (!psThreadPoolWait(true, true)) {
             psError(PS_ERR_UNKNOWN, false, "Unable to flat-field image.");
             return false;
Index: trunk/psModules/src/detrend/pmShutterCorrection.c
===================================================================
--- trunk/psModules/src/detrend/pmShutterCorrection.c	(revision 33083)
+++ trunk/psModules/src/detrend/pmShutterCorrection.c	(revision 33089)
@@ -805,5 +805,5 @@
         if (threaded) {
             // wait here for the threaded jobs to finish
-            if (!psThreadPoolWait(true)) {
+            if (!psThreadPoolWait(true, true)) {
                 psError(PS_ERR_UNKNOWN, false, "Unable to apply shutter correction.");
                 psFree(shutterImage);
Index: trunk/psModules/src/imcombine/pmStackReject.c
===================================================================
--- trunk/psModules/src/imcombine/pmStackReject.c	(revision 33083)
+++ trunk/psModules/src/imcombine/pmStackReject.c	(revision 33089)
@@ -313,5 +313,5 @@
     }
 
-    if (!psThreadPoolWait(false)) {
+    if (!psThreadPoolWait(false, true)) {
         psError(psErrorCodeLast(), false, "Unable to grow bad pixels.");
         psFree(source);
Index: trunk/psModules/src/imcombine/pmSubtraction.c
===================================================================
--- trunk/psModules/src/imcombine/pmSubtraction.c	(revision 33083)
+++ trunk/psModules/src/imcombine/pmSubtraction.c	(revision 33089)
@@ -905,5 +905,5 @@
         }
     }
-    if (!psThreadPoolWait(true)) {
+    if (!psThreadPoolWait(true, true)) {
         psError(psErrorCodeLast(), false, "Error waiting for threads.");
         return false;
@@ -1427,5 +1427,5 @@
     }
 
-    if (!psThreadPoolWait(false)) {
+    if (!psThreadPoolWait(false, true)) {
         psError(psErrorCodeLast(), false, "Error waiting for threads.");
         return false;
Index: trunk/psModules/src/imcombine/pmSubtractionEquation.c
===================================================================
--- trunk/psModules/src/imcombine/pmSubtractionEquation.c	(revision 33083)
+++ trunk/psModules/src/imcombine/pmSubtractionEquation.c	(revision 33089)
@@ -958,5 +958,5 @@
     }
 
-    if (!psThreadPoolWait(true)) {
+    if (!psThreadPoolWait(true, true)) {
         psError(psErrorCodeLast(), false, "Error waiting for threads.");
         return false;
Index: trunk/psModules/src/imcombine/pmSubtractionEquation.v0.c
===================================================================
--- trunk/psModules/src/imcombine/pmSubtractionEquation.v0.c	(revision 33083)
+++ trunk/psModules/src/imcombine/pmSubtractionEquation.v0.c	(revision 33089)
@@ -882,5 +882,5 @@
     }
 
-    if (!psThreadPoolWait(true)) {
+    if (!psThreadPoolWait(true, true)) {
         psError(psErrorCodeLast(), false, "Error waiting for threads.");
         return false;
Index: trunk/psModules/src/imcombine/pmSubtractionMatch.c
===================================================================
--- trunk/psModules/src/imcombine/pmSubtractionMatch.c	(revision 33083)
+++ trunk/psModules/src/imcombine/pmSubtractionMatch.c	(revision 33089)
@@ -1091,5 +1091,5 @@
     }
 
-    if (!psThreadPoolWait(true)) {
+    if (!psThreadPoolWait(true, true)) {
 	psError(psErrorCodeLast(), false, "Error waiting for threads.");
 	psFree(models);
Index: trunk/psphot/src/psphotApResid.c
===================================================================
--- trunk/psphot/src/psphotApResid.c	(revision 33083)
+++ trunk/psphot/src/psphotApResid.c	(revision 33089)
@@ -154,6 +154,7 @@
 
         // wait for the threads to finish and manage results
-        if (!psThreadPoolWait (false)) {
+        if (!psThreadPoolWait (false, true)) {
             psError(PS_ERR_UNKNOWN, false, "Unable to guess model.");
+            psFree(cellGroups);
             return false;
         }
Index: trunk/psphot/src/psphotBlendFit.c
===================================================================
--- trunk/psphot/src/psphotBlendFit.c	(revision 33083)
+++ trunk/psphot/src/psphotBlendFit.c	(revision 33089)
@@ -151,5 +151,5 @@
 
         // wait for the threads to finish and manage results
-        if (!psThreadPoolWait (false)) {
+        if (!psThreadPoolWait (false, true)) {
             psError(PS_ERR_UNKNOWN, false, "Unable to guess model.");
 	    psFree (fitOptions);
Index: trunk/psphot/src/psphotExtendedSourceAnalysis.c
===================================================================
--- trunk/psphot/src/psphotExtendedSourceAnalysis.c	(revision 33083)
+++ trunk/psphot/src/psphotExtendedSourceAnalysis.c	(revision 33089)
@@ -134,5 +134,5 @@
 
         // wait for the threads to finish and manage results
-        if (!psThreadPoolWait (false)) {
+        if (!psThreadPoolWait (false, true)) {
             psError(PS_ERR_UNKNOWN, false, "Unable to guess model.");
 	    psFree(AnalysisRegion);
Index: trunk/psphot/src/psphotExtendedSourceFits.c
===================================================================
--- trunk/psphot/src/psphotExtendedSourceFits.c	(revision 33083)
+++ trunk/psphot/src/psphotExtendedSourceFits.c	(revision 33089)
@@ -218,5 +218,5 @@
 
         // wait for the threads to finish and manage results
-        if (!psThreadPoolWait (false)) {
+        if (!psThreadPoolWait (false, true)) {
             psError(PS_ERR_UNKNOWN, false, "Unable to guess model.");
 	    psFree(AnalysisRegion);
Index: trunk/psphot/src/psphotFindFootprints.c
===================================================================
--- trunk/psphot/src/psphotFindFootprints.c	(revision 33083)
+++ trunk/psphot/src/psphotFindFootprints.c	(revision 33089)
@@ -35,7 +35,12 @@
         psArray *tmp = pmFootprintArrayGrow(footprints, growRadius);
         psImageConvolveSetThreads(oldThreads);
-        psLogMsg ("psphot", PS_LOG_MINUTIA, "grow footprint coverage by %d pixels, %ld footprints become %ld footprints: %f sec\n", growRadius, footprints->n, tmp->n, psTimerMark ("psphot.footprints"));
-        psFree(footprints);
-        footprints = tmp;
+        psLogMsg ("psphot", PS_LOG_MINUTIA, "grow footprint coverage by %d pixels, %ld footprints become %ld footprints: %f sec\n", growRadius, footprints->n, tmp ? tmp->n : 0, psTimerMark ("psphot.footprints"));
+        if (tmp) {
+            psFree(footprints);
+            footprints = tmp;
+        } else {
+            psLogMsg ("psphot", PS_LOG_WARN, "pmFootprintArray grow returned NULL\n");
+        }
+            
     }
 
Index: trunk/psphot/src/psphotGuessModels.c
===================================================================
--- trunk/psphot/src/psphotGuessModels.c	(revision 33083)
+++ trunk/psphot/src/psphotGuessModels.c	(revision 33089)
@@ -112,5 +112,7 @@
         // wait here for the threaded jobs to finish
         // fprintf (stderr, "wait for threads (%d, %d)\n", jx, jy);
-        if (!psThreadPoolWait (false)) {
+        if (!psThreadPoolWait (false, true)) {
+            // harvest our jobs
+            psFree(cellGroups);
             psError(PS_ERR_UNKNOWN, false, "Unable to guess model.");
             return false;
Index: trunk/psphot/src/psphotKronIterate.c
===================================================================
--- trunk/psphot/src/psphotKronIterate.c	(revision 33083)
+++ trunk/psphot/src/psphotKronIterate.c	(revision 33089)
@@ -158,5 +158,5 @@
 
         // wait for the threads to finish and manage results
-        if (!psThreadPoolWait (false)) {
+        if (!psThreadPoolWait (false, true)) {
             psError(PS_ERR_UNKNOWN, false, "Unable to guess model.");
             return false;
Index: trunk/psphot/src/psphotMagnitudes.c
===================================================================
--- trunk/psphot/src/psphotMagnitudes.c	(revision 33083)
+++ trunk/psphot/src/psphotMagnitudes.c	(revision 33089)
@@ -129,5 +129,5 @@
 
         // wait for the threads to finish and manage results
-        if (!psThreadPoolWait (false)) {
+        if (!psThreadPoolWait (false, true)) {
             psError(PS_ERR_UNKNOWN, false, "Unable to guess model.");
             return false;
@@ -309,5 +309,5 @@
 
         // wait for the threads to finish and manage results
-        if (!psThreadPoolWait (false)) {
+        if (!psThreadPoolWait (false, true)) {
             psError(PS_ERR_UNKNOWN, false, "Unable to guess model.");
             return false;
Index: trunk/psphot/src/psphotRadialApertures.c
===================================================================
--- trunk/psphot/src/psphotRadialApertures.c	(revision 33083)
+++ trunk/psphot/src/psphotRadialApertures.c	(revision 33089)
@@ -176,5 +176,5 @@
 
         // wait for the threads to finish and manage results
-        if (!psThreadPoolWait (false)) {
+        if (!psThreadPoolWait (false, true)) {
             psError(PS_ERR_UNKNOWN, false, "Unable to guess model.");
 	    psFree(AnalysisRegion);
Index: trunk/psphot/src/psphotRadialProfileWings.c
===================================================================
--- trunk/psphot/src/psphotRadialProfileWings.c	(revision 33083)
+++ trunk/psphot/src/psphotRadialProfileWings.c	(revision 33089)
@@ -147,5 +147,5 @@
 
         // wait for the threads to finish and manage results
-        if (!psThreadPoolWait (false)) {
+        if (!psThreadPoolWait (false, true)) {
             psError(PS_ERR_UNKNOWN, false, "Unable to guess model.");
             return false;
Index: trunk/psphot/src/psphotReadout.c
===================================================================
--- trunk/psphot/src/psphotReadout.c	(revision 33083)
+++ trunk/psphot/src/psphotReadout.c	(revision 33089)
@@ -133,5 +133,9 @@
     // Construct an initial model for each object, set the radius to fitRadius, set circular
     // fit mask.  NOTE: only applied to sources without guess models
-    psphotGuessModels (config, view, filerule); // pass 1
+    // pass 1
+    if (!psphotGuessModels (config, view, filerule)) {
+        psLogMsg ("psphot", 3, "failure to Guess Model - pass 1");
+        return psphotReadoutCleanup (config, view, filerule);
+    }
 
     // linear PSF fit to source peaks, subtract the models from the image (in PSF mask)
@@ -155,4 +159,5 @@
     // non-linear PSF and EXT fit to brighter sources
     // replace model flux, adjust mask as needed, fit, subtract the models (full stamp)
+    // XXX: can leave faulted job in done queue
     psphotBlendFit (config, view, filerule); // pass 1 (detections->allSources)
 
Index: trunk/psphot/src/psphotSourceStats.c
===================================================================
--- trunk/psphot/src/psphotSourceStats.c	(revision 33083)
+++ trunk/psphot/src/psphotSourceStats.c	(revision 33089)
@@ -216,5 +216,5 @@
 
         // wait for the threads to finish and manage results
-        if (!psThreadPoolWait (false)) {
+        if (!psThreadPoolWait (false, true)) {
             psError(PS_ERR_UNKNOWN, false, "Failure in thread job PSPHOT_SOURCE_STATS");
             psFree(detections->newSources);
@@ -347,5 +347,5 @@
 
         // wait for the threads to finish and manage results
-        if (!psThreadPoolWait (false)) {
+        if (!psThreadPoolWait (false, true)) {
             psError(PS_ERR_UNKNOWN, false, "Failure in thread job PSPHOT_SOURCE_STATS");
             return NULL;
Index: trunk/psphot/src/psphotTest.c
===================================================================
--- trunk/psphot/src/psphotTest.c	(revision 33083)
+++ trunk/psphot/src/psphotTest.c	(revision 33089)
@@ -85,5 +85,5 @@
 
     // wait for the threads to finish and manage results
-    if (!psThreadPoolWait (true)) {
+    if (!psThreadPoolWait (true, true)) {
         fprintf (stderr, "failure to run FillImage (2)");
         exit (1);
