janhq/jan · error

RAG extension not available

Error message

RAG extension not available

What it means

Thrown when the RAG extension is not registered with the ExtensionManager or it does not expose ingestAttachments. The service relies on ExtensionManager.getInstance().get<RAGExtension>(ExtensionTypeEnum.RAG) and requires both the extension object and its ingestAttachments method.

Solutions

  1. Ensure the RAG extension is installed and registered with the ExtensionManager before any ingestion call
  2. Verify the @janhq/core version's RAGExtension still declares ingestAttachments and update the extension implementation accordingly
  3. Check registration order — extensions must be registered before uploads are triggered (e.g. gate the upload UI until extensions are ready)

Example fix

// before
const ext = ExtensionManager.getInstance().get<RAGExtension>(ExtensionTypeEnum.RAG)
await uploads.ingestFileAttachment(threadId, att)
// after
const ext = ExtensionManager.getInstance().get<RAGExtension>(ExtensionTypeEnum.RAG)
if (!ext?.ingestAttachments) throw new Error('RAG extension must be registered before uploading documents')
await uploads.ingestFileAttachment(threadId, att)
Defensive patterns

Strategy: validation

Validate before calling

const ext = ExtensionManager.getInstance().get<RAGExtension>(ExtensionTypeEnum.RAG)
if (!ext?.ingestAttachments) throw new Error('RAG extension with ingestAttachments must be registered before uploading documents')

Type guard

const hasRagIngest = (): boolean =>
  !!ExtensionManager.getInstance().get<RAGExtension>(ExtensionTypeEnum.RAG)?.ingestAttachments

Try / catch

try {
  await uploads.ingestFileAttachment(threadId, att)
} catch (e) {
  if (e instanceof Error && e.message === 'RAG extension not available') {
    showExtensionSetupPrompt('Install/enable the RAG extension to upload documents')
    return
  }
  throw e
}

Prevention

When it happens

Trigger: Calling ingestFileAttachment when no extension is registered under ExtensionTypeEnum.RAG, or the registered extension lacks an ingestAttachments implementation (ext is null or ext.ingestAttachments is undefined).

Common situations: The RAG extension was never installed/registered at app startup; extension registration runs after the upload call; a core version upgrade renamed or removed ingestAttachments from the RAGExtension interface.

Understand the failure class

Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.

Related errors


AI-assisted analysis of janhq/jan@7205d770c1 (2026-09-17). Data as JSON: /api/errors/783a4a1d55645287. Report an issue: GitHub.

Appendix: 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 7205d770c1)