{"record":{"id":"e99a1610842ff150","repo":"janhq/jan","slug":"failed-to-ingest-file","errorCode":null,"errorMessage":"Failed to ingest file","messagePattern":"Failed to ingest file","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"web-app/src/stores/project-uploads-store.ts","lineNumber":77,"sourceCode":"        currentFileName = att.name\n\n        set((s) => {\n          const existing = s.progress[projectId]\n          if (!existing) return s\n          return {\n            progress: {\n              ...s.progress,\n              [projectId]: {\n                ...existing,\n                current: i,\n                currentFileName: att.name,\n              },\n            },\n          }\n        })\n\n        const result = await ingestFn(projectId, att)\n        if (!result.id) throw new Error('Failed to ingest file')\n\n        set((s) => {\n          const existing = s.progress[projectId]\n          const nextTick = (s.completedTick[projectId] ?? 0) + 1\n          return {\n            progress: existing\n              ? {\n                  ...s.progress,\n                  [projectId]: { ...existing, current: i + 1 },\n                }\n              : s.progress,\n            completedTick: { ...s.completedTick, [projectId]: nextTick },\n          }\n        })\n      }\n      handlers.onSuccess()\n    } catch (error) {\n      handlers.onError(error, currentFileName)","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/janhq/jan/blob/7205d770c1e097c3daf35a911176410e93bc5564/web-app/src/stores/project-uploads-store.ts#L59-L95","documentation":"In project-uploads-store, after await ingestFn(projectId, att) resolves, the store requires result.id to build its progress state; if the UploadResult has no id it throws 'Failed to ingest file'. This wraps any ingestion whose result lacked an identifier (including the upstream 'Failed to resolve ingested attachment id' path producing an id-less result).","triggerScenarios":"ingestFn (ingestFileAttachmentForProject or equivalent) resolves successfully but its returned object has no id — e.g. the RAG extension returned no files so the service result was constructed without an id, or ingestFn itself returned an id-less UploadResult.","commonSituations":"RAG extension/backend returned an empty files array; a mocked or placeholder ingest implementation returned { } or { id: undefined }; a swallowed upstream error was converted into a partial result object.","solutions":["Fix the upstream service so it throws instead of returning an id-less UploadResult when the extension yields no file id","Validate result.id in the store and surface the underlying cause (log res/files) rather than a generic message","If using a placeholder/mock ingestFn, make it return { id: ulid() } like DefaultUploadsService.ingestImage does"],"exampleFix":"// before\nconst result = await ingestFn(projectId, att)\nif (!result.id) throw new Error('Failed to ingest file')\n// after\nconst result = await ingestFn(projectId, att)\nif (!result?.id) {\n  throw new Error(`Failed to ingest file ${att.name}: ingestion returned no id`)\n}","handlingStrategy":"validation","validationCode":"if (!result || typeof result.id !== 'string') throw new Error(`Ingestion for ${att.name} returned no id`)","typeGuard":"const hasUploadId = (r: UploadResult | undefined): r is UploadResult & { id: string } =>\n  typeof r?.id === 'string' && r.id.length > 0","tryCatchPattern":"try {\n  const result = await ingestFn(projectId, att)\n  if (!hasUploadId(result)) throw new Error(`Failed to ingest ${att.name}: no id returned`)\n  // proceed with progress update\n} catch (e) {\n  setUploadFailed(projectId, att, e instanceof Error ? e.message : String(e))\n  throw e\n}","preventionTips":["Make ingest services throw on unusable responses instead of returning id-less UploadResults","Add a store-level invariant test that every successful ingestion path yields a string id","Keep mock/placeholder ingest implementations returning real ulid ids so store logic is exercised identically"],"tags":["store","ingestion","empty-result"],"backgroundTag":"empty-result-set","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"}