{"record":{"id":"5ebce1326fddc237","repo":"janhq/jan","slug":"no-id-returned-from-image-ingestion","errorCode":null,"errorMessage":"No ID returned from image ingestion","messagePattern":"No ID returned from image ingestion","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web-app/src/containers/ChatInput.tsx","lineNumber":1384,"sourceCode":"              const result = await serviceHub\n                .uploads()\n                .ingestImage(currentThreadId, img)\n\n              if (result?.id) {\n                setAttachmentsForThread(attachmentsKey, (prev) =>\n                  prev.map((a) =>\n                    matchImg(a)\n                      ? {\n                          ...a,\n                          processing: false,\n                          processed: true,\n                          id: result.id,\n                        }\n                      : a\n                  )\n                )\n              } else {\n                throw new Error('No ID returned from image ingestion')\n              }\n            } catch (error) {\n              console.error('Failed to ingest image:', error)\n              setAttachmentsForThread(attachmentsKey, (prev) =>\n                prev.filter((a) => !matchImg(a))\n              )\n              toast.error(`Failed to ingest ${img.name}`, {\n                description:\n                  error instanceof Error ? error.message : String(error),\n              })\n            } finally {\n              setFileIngestProgress({\n                completed: i + 1,\n                total: ingestTotal,\n              })\n            }\n          }\n        } finally {","sourceCodeStart":1366,"sourceCodeEnd":1402,"githubUrl":"https://github.com/janhq/jan/blob/7205d770c1e097c3daf35a911176410e93bc5564/web-app/src/containers/ChatInput.tsx#L1366-L1402","documentation":"After uploading an image for ingestion the code expects the response to include an id, which it writes back into the attachment state. If result.id is missing the upload is treated as failed: the error is thrown, caught, logged, and the in-progress attachment is removed from state.","triggerScenarios":"The image ingestion endpoint returns a 2xx response whose JSON body lacks an id field (e.g. older backend, wrong endpoint, error-shaped body with 200 status, or result being undefined after a failed JSON parse).","commonSituations":"Backend/API version drift where the ingestion response shape changed; a proxy returning an HTML error page with 200; attaching images while pointing the app at a misconfigured or stale server.","solutions":["Check the ingestion endpoint response body in devtools/network tab and confirm it contains id.","Verify the frontend and backend ingestion API contract versions match.","Validate the parsed response before consuming it and surface a clearer server error message.","Retry the upload; transient gateway issues can return malformed empty bodies."],"exampleFix":"// before\n} else {\n  throw new Error('No ID returned from image ingestion')\n}\n// after\n} else {\n  throw new Error(\n    `No ID returned from image ingestion: ${JSON.stringify(result).slice(0, 200)}`\n  )\n}","handlingStrategy":"validation","validationCode":"const ingestResponse = await res.json()\nif (!ingestResponse || typeof ingestResponse.id !== 'string' || !ingestResponse.id) {\n  throw new Error(`Image ingestion returned invalid response: ${JSON.stringify(ingestResponse)}`)\n}","typeGuard":"function hasIngestionId(r: unknown): r is { id: string } {\n  return typeof r === 'object' && r !== null && 'id' in r && typeof (r as { id: unknown }).id === 'string'\n}","tryCatchPattern":"try {\n  const result = await ingestImage(file)\n  if (!result?.id) throw new Error('No ID returned from image ingestion')\n} catch (error) {\n  console.error('Failed to ingest image:', error)\n  toast.error('Image upload failed. Please try again.')\n  setAttachmentsForThread(attachmentsKey, prev => prev.filter(a => !matchImg(a)))\n}","preventionTips":["Validate ingestion responses against a schema (zod) before consuming.","Keep frontend/backend API contracts versioned and tested.","Check network tab for HTML/empty bodies masquerading as 200 responses.","Surface failed attachments to the user instead of silently removing them."],"tags":["upload","api","attachments"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"7205d770c1e097c3daf35a911176410e93bc5564","analyzedAt":"2026-09-17T14:27:30.100Z","contentChangedAt":"2026-09-17T14:27:30.100Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}