janhq/jan · error · Error

Failed to ingest file

Error message

Failed to ingest file

What it means

Thrown by the project-uploads zustand store during its ingest loop when ingestFn(projectId, att) resolved but result.id is falsy. It stops the batch and reports the failing file via handlers.onError(error, currentFileName). It is the store-level wrapper over upstream upload-service failures (e.g., cascading from errors 172/173).

Source

Thrown at web-app/src/stores/project-uploads-store.ts:77

        currentFileName = att.name

        set((s) => {
          const existing = s.progress[projectId]
          if (!existing) return s
          return {
            progress: {
              ...s.progress,
              [projectId]: {
                ...existing,
                current: i,
                currentFileName: att.name,
              },
            },
          }
        })

        const result = await ingestFn(projectId, att)
        if (!result.id) throw new Error('Failed to ingest file')

        set((s) => {
          const existing = s.progress[projectId]
          const nextTick = (s.completedTick[projectId] ?? 0) + 1
          return {
            progress: existing
              ? {
                  ...s.progress,
                  [projectId]: { ...existing, current: i + 1 },
                }
              : s.progress,
            completedTick: { ...s.completedTick, [projectId]: nextTick },
          }
        })
      }
      handlers.onSuccess()
    } catch (error) {
      handlers.onError(error, currentFileName)

View on GitHub (pinned to fad3f12a14)

Solutions

  1. Inspect the underlying ingestFn - usually ingestFileAttachmentForProject - for why no id came back (see errors 172/173).
  2. Check the RAG backend logs for the specific file named in onError.
  3. Validate file type/size before adding files to the batch.

Example fix

// before: a single missing id aborts the whole batch
const result = await ingestFn(projectId, att)
if (!result.id) throw new Error('Failed to ingest file')
// after: collect per-file failures and continue
const result = await ingestFn(projectId, att)
if (!result.id) { failed.push(att.name); continue }
Defensive patterns

Strategy: try-catch

Validate before calling

function hasIngestId(r: { id?: string } | null | undefined): boolean { return !!r?.id }

Type guard

function isIngestSuccess(r: unknown): r is { id: string } {
  return typeof (r as any)?.id === 'string' && !!((r as any).id)
}

Try / catch

await useProjectUploads.getState().ingest(pid, attachments, ingestFn, {
  onSuccess: () => refreshFiles(pid),
  onError: (e, fileName) => toast.error(`Failed to ingest ${fileName ?? 'file'}`),
})

Prevention

When it happens

Trigger: For some attachment in the batch, ingestFn returned a result whose id is undefined/null/empty-string. The store throws 'Failed to ingest file', which is caught by the surrounding try and routed to handlers.onError with the current file name.

Common situations: Underlying upload service (DefaultUploadsService.ingestFileAttachmentForProject) returned no id; project RAG backend silently rejected the file; integration returned a malformed result object.

Related errors


AI-assisted analysis of janhq/jan@fad3f12a14 (2026-08-12). Data as JSON: /api/errors/e99a1610842ff150. Report an issue: GitHub.