janhq/jan · error · Error

RAG extension not available

Error message

RAG extension not available

What it means

Thrown by ingestFileAttachment when the RAG extension is not registered or does not expose ingestAttachments. Document ingestion depends on the RAG extension; without that capability the operation cannot proceed.

Source

Thrown at web-app/src/services/uploads/default.ts:18

import type { UploadsService, UploadResult } from './types'
import type { Attachment } from '@/types/attachment'
import { ulid } from 'ulidx'
import { ExtensionManager } from '@/lib/extension'
import { ExtensionTypeEnum, type RAGExtension, type IngestAttachmentsResult } from '@janhq/core'

export class DefaultUploadsService implements UploadsService {
  async ingestImage(_threadId: string, attachment: Attachment): Promise<UploadResult> {
    if (attachment.type !== 'image') throw new Error('ingestImage: attachment is not image')
    // Placeholder upload flow; swap for real API call when backend is ready
    await new Promise((r) => setTimeout(r, 100))
    return { id: ulid() }
  }

  async ingestFileAttachment(threadId: string, attachment: Attachment): Promise<UploadResult> {
    if (attachment.type !== 'document') throw new Error('ingestFileAttachment: attachment is not document')
    const ext = ExtensionManager.getInstance().get<RAGExtension>(ExtensionTypeEnum.RAG)
    if (!ext?.ingestAttachments) throw new Error('RAG extension not available')
    const res: IngestAttachmentsResult = await ext.ingestAttachments(threadId, [
      { path: attachment.path!, name: attachment.name, type: attachment.fileType, size: attachment.size },
    ])
    const files = res.files
    if (Array.isArray(files) && files[0]?.id) {
      return {
        id: files[0].id,
        size: typeof files[0].size === 'number' ? Number(files[0].size) : undefined,
        chunkCount: typeof files[0].chunk_count === 'number' ? Number(files[0].chunk_count) : undefined,
      }
    }
    throw new Error('Failed to resolve ingested attachment id')
  }

  async ingestFileAttachmentForProject(projectId: string, attachment: Attachment): Promise<UploadResult> {
    if (attachment.type !== 'document') throw new Error('ingestFileAttachmentForProject: attachment is not document')
    const ext = ExtensionManager.getInstance().get<RAGExtension>(ExtensionTypeEnum.RAG)
    if (!ext?.ingestAttachmentsForProject) throw new Error('RAG extension does not support project-level ingestion')

View on GitHub (pinned to fad3f12a14)

Solutions

  1. Ensure the RAG extension is enabled and loaded before offering document uploads.
  2. Retry once shortly after startup in case of a registration race.
  3. If unavailable, disable the document-upload UI affordance.

Example fix

// before: throw when RAG missing
const ext = ExtensionManager.getInstance().get<RAGExtension>(ExtensionTypeEnum.RAG)
if (!ext?.ingestAttachments) throw new Error('RAG extension not available')
// after: gate the UI on capability
const ext = ExtensionManager.getInstance().get<RAGExtension>(ExtensionTypeEnum.RAG)
if (!ext?.ingestAttachments) { setDocUploadEnabled(false); return }
Defensive patterns

Strategy: validation

Validate before calling

function isRagAvailable(): boolean {
  return !!ExtensionManager.getInstance().get<RAGExtension>(ExtensionTypeEnum.RAG)?.ingestAttachments
}

Type guard

function hasIngestAttachments(e: unknown): e is RAGExtension {
  return !!e && typeof (e as RAGExtension).ingestAttachments === 'function'
}

Prevention

When it happens

Trigger: ExtensionManager.get<RAGExtension>(ExtensionTypeEnum.RAG) returns undefined, OR the returned object has no ingestAttachments function - so !ext?.ingestAttachments is true.

Common situations: RAG extension disabled or not installed; startup race where RAG is not registered yet; extension built without the ingestion capability.

Related errors


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