fix(admin): stop reporting every removeImageBackground failure as a sidecar failure (#281)
The remove-background route's catch block turned every throw from removeImageBackground into a 502 "the background-removal service did not answer". But removeImageBackground also throws for an unrecognised file extension (a legacy .jpeg), for a file missing from the uploads volume, and when REMBG_URL is not set at all — none of which involve contacting the sidecar. The admin was told to retry a service that was never reached, while the real reason existed only in the server log. Added SidecarRequestError in rembgClient.ts, following the NoOriginalToRestoreError pattern already in backgroundRemoval.ts. It is thrown only for failures that happen after actually attempting to reach the sidecar: the fetch call itself throwing (now wrapped in a try/catch, covering unreachable and timed-out), a non-2xx response, or a response that is not a PNG. It is deliberately not thrown for "REMBG_URL is not set", since that path never attempts contact at all. The remove-background handler now checks err instanceof SidecarRequestError before answering 502; everything else answers 500 with a message that says what actually went wrong. Added a unit test pairing (rembgClient.test.ts) asserting the sidecar-contacted failures are SidecarRequestError and the unconfigured case is not, and an integration test (adminItemDrafts.integration.test.ts) proving a missing upload file answers something other than 502 with a message that does not claim the service did not answer. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -8,7 +8,7 @@ import {
|
||||
removeImageBackground,
|
||||
restoreImageOriginal,
|
||||
} from '../intake/backgroundRemoval';
|
||||
import { isRembgConfigured } from '../intake/rembgClient';
|
||||
import { isRembgConfigured, SidecarRequestError } from '../intake/rembgClient';
|
||||
|
||||
const router = Router();
|
||||
|
||||
@@ -274,13 +274,32 @@ router.post(
|
||||
try {
|
||||
await removeImageBackground(Number(imageId));
|
||||
} catch (err) {
|
||||
// 502, not 500. The request was fine and so is this app — the service it
|
||||
// depends on did not answer. The message says the photo is unchanged,
|
||||
// because that is the thing the admin actually needs to know.
|
||||
console.error(`[drafts] background removal for image ${imageId}:`, err);
|
||||
return res
|
||||
.status(502)
|
||||
.json({ error: 'the background-removal service did not answer — the photo is unchanged' });
|
||||
|
||||
// 502 only for a SidecarRequestError: the request was fine and so is
|
||||
// this app — the service it depends on was actually contacted and did
|
||||
// not answer usably. The message says the photo is unchanged, because
|
||||
// that is the thing the admin actually needs to know.
|
||||
if (err instanceof SidecarRequestError) {
|
||||
return res
|
||||
.status(502)
|
||||
.json({ error: 'the background-removal service did not answer — the photo is unchanged' });
|
||||
}
|
||||
|
||||
// Everything else here never reached the sidecar at all — an
|
||||
// unrecognised file extension (a legacy .jpeg), a file missing from the
|
||||
// uploads volume, or REMBG_URL not being set. Reporting those as "the
|
||||
// service did not answer" would send the admin to retry a service that
|
||||
// was never contacted, and hide the real reason in the server log. The
|
||||
// photo is still unchanged in every one of these cases too:
|
||||
// removeImageBackground only writes the row once the cut-out already
|
||||
// exists on disk.
|
||||
return res.status(500).json({
|
||||
error:
|
||||
err instanceof Error
|
||||
? `this photo could not be processed: ${err.message}`
|
||||
: 'this photo could not be processed'
|
||||
});
|
||||
}
|
||||
|
||||
res.json(await imageOfItem(itemId, imageId));
|
||||
|
||||
Reference in New Issue
Block a user