janhq/jan · error · Error

No ID returned from image ingestion

Error message

No ID returned from image ingestion

What it means

This error is thrown in the React frontend when serviceHub.uploads().ingestImage() resolves successfully but the returned object has no id property (or id is falsy). The image ingestion pipeline is expected to return an object with an id field representing the stored vector/embedding. A missing id means the backend accepted the request but did not return a valid identifier, making the attachment unusable for retrieval.

Source

Thrown at web-app/src/containers/ChatInput.tsx:1091

              const result = await serviceHub
                .uploads()
                .ingestImage(currentThreadId, img)

              if (result?.id) {
                setAttachmentsForThread(attachmentsKey, (prev) =>
                  prev.map((a) =>
                    matchImg(a)
                      ? {
                          ...a,
                          processing: false,
                          processed: true,
                          id: result.id,
                        }
                      : a
                  )
                )
              } else {
                throw new Error('No ID returned from image ingestion')
              }
            } catch (error) {
              console.error('Failed to ingest image:', error)
              setAttachmentsForThread(attachmentsKey, (prev) =>
                prev.filter((a) => !matchImg(a))
              )
              toast.error(`Failed to ingest ${img.name}`, {
                description:
                  error instanceof Error ? error.message : String(error),
              })
            } finally {
              setFileIngestProgress({
                completed: i + 1,
                total: ingestTotal,
              })
            }
          }
        } finally {

View on GitHub (pinned to fad3f12a14)

Solutions

  1. Verify the vector-db plugin is initialized and healthy before ingesting images.
  2. Check the backend ingestImage command's return type matches { id: string }.
  3. Log the full result object to inspect the actual response shape.
  4. Ensure the SQLite/vector store has the correct schema for image embeddings.

Example fix

// before
const result = await serviceHub.uploads().ingestImage(currentThreadId, img)
if (result?.id) { /* use result.id */ }
else { throw new Error('No ID returned from image ingestion') }

// after
const result = await serviceHub.uploads().ingestImage(currentThreadId, img)
const id = result?.id ?? result?.uuid ?? result?._id
if (!id) {
  console.error('Unexpected ingest result shape:', JSON.stringify(result))
  throw new Error(`No ID returned from image ingestion: ${JSON.stringify(result)}`)
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Before using the result, validate its shape
interface IngestResult { id: string }

function isIngestResult(v: unknown): v is IngestResult {
  return typeof v === 'object' && v !== null &&
    typeof (v as Record<string, unknown>).id === 'string' &&
    (v as Record<string, unknown>).id!.length > 0;
}

const result = await serviceHub.uploads().ingestImage(currentThreadId, img);
if (!isIngestResult(result)) {
  console.error('Unexpected ingest result:', JSON.stringify(result));
  throw new Error(`No ID returned from image ingestion: ${JSON.stringify(result)}`);
}

Type guard

function hasValidId(v: unknown): v is { id: string } {
  return typeof v === 'object' && v !== null &&
    typeof (v as Record<string, unknown>).id === 'string' &&
    ((v as Record<string, unknown>).id as string).length > 0;
}

Try / catch

try {
  const result = await serviceHub.uploads().ingestImage(currentThreadId, img);
  if (!result?.id) {
    throw new Error(`No ID returned: ${JSON.stringify(result)}`);
  }
  // use result.id
} catch (error) {
  setAttachmentsForThread(attachmentsKey, (prev) => prev.filter((a) => !matchImg(a)));
  toast.error(`Failed to ingest ${img.name}`, {
    description: error instanceof Error ? error.message : String(error),
  });
}

Prevention

When it happens

Trigger: The vector-db plugin's ingestImage command returns an empty or null result object. The backend stored the image but failed to return the generated ID (serialization issue). A race condition where the result is partially constructed. The backend returned a different response shape than expected (e.g. { uuid } instead of { id }).

Common situations: Vector database not initialized when ingestion is attempted. Plugin version mismatch changing the response contract. Backend returning { ok: true } without an id. SQLite insert succeeded but last_insert_rowid() returned 0. Network/IPC serialization dropping the id field.

Related errors


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