{"record":{"id":"783a4a1d55645287","repo":"janhq/jan","slug":"rag-extension-not-available","errorCode":null,"errorMessage":"RAG extension not available","messagePattern":"RAG extension not available","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"web-app/src/services/uploads/default.ts","lineNumber":18,"sourceCode":"import type { UploadsService, UploadResult } from './types'\nimport type { Attachment } from '@/types/attachment'\nimport { ulid } from 'ulidx'\nimport { ExtensionManager } from '@/lib/extension'\nimport { ExtensionTypeEnum, type RAGExtension, type IngestAttachmentsResult } from '@janhq/core'\n\nexport class DefaultUploadsService implements UploadsService {\n  async ingestImage(_threadId: string, attachment: Attachment): Promise<UploadResult> {\n    if (attachment.type !== 'image') throw new Error('ingestImage: attachment is not image')\n    // Placeholder upload flow; swap for real API call when backend is ready\n    await new Promise((r) => setTimeout(r, 100))\n    return { id: ulid() }\n  }\n\n  async ingestFileAttachment(threadId: string, attachment: Attachment): Promise<UploadResult> {\n    if (attachment.type !== 'document') throw new Error('ingestFileAttachment: attachment is not document')\n    const ext = ExtensionManager.getInstance().get<RAGExtension>(ExtensionTypeEnum.RAG)\n    if (!ext?.ingestAttachments) throw new Error('RAG extension not available')\n    const res: IngestAttachmentsResult = await ext.ingestAttachments(threadId, [\n      { path: attachment.path!, name: attachment.name, type: attachment.fileType, size: attachment.size },\n    ])\n    const files = res.files\n    if (Array.isArray(files) && files[0]?.id) {\n      return {\n        id: files[0].id,\n        size: typeof files[0].size === 'number' ? Number(files[0].size) : undefined,\n        chunkCount: typeof files[0].chunk_count === 'number' ? Number(files[0].chunk_count) : undefined,\n      }\n    }\n    throw new Error('Failed to resolve ingested attachment id')\n  }\n\n  async ingestFileAttachmentForProject(projectId: string, attachment: Attachment): Promise<UploadResult> {\n    if (attachment.type !== 'document') throw new Error('ingestFileAttachmentForProject: attachment is not document')\n    const ext = ExtensionManager.getInstance().get<RAGExtension>(ExtensionTypeEnum.RAG)\n    if (!ext?.ingestAttachmentsForProject) throw new Error('RAG extension does not support project-level ingestion')","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/janhq/jan/blob/7205d770c1e097c3daf35a911176410e93bc5564/web-app/src/services/uploads/default.ts#L1-L36","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Ensure the RAG extension is installed and registered with the ExtensionManager before any ingestion call","Verify the @janhq/core version's RAGExtension still declares ingestAttachments and update the extension implementation accordingly","Check registration order — extensions must be registered before uploads are triggered (e.g. gate the upload UI until extensions are ready)"],"exampleFix":"// before\nconst ext = ExtensionManager.getInstance().get<RAGExtension>(ExtensionTypeEnum.RAG)\nawait uploads.ingestFileAttachment(threadId, att)\n// after\nconst ext = ExtensionManager.getInstance().get<RAGExtension>(ExtensionTypeEnum.RAG)\nif (!ext?.ingestAttachments) throw new Error('RAG extension must be registered before uploading documents')\nawait uploads.ingestFileAttachment(threadId, att)","handlingStrategy":"validation","validationCode":"const ext = ExtensionManager.getInstance().get<RAGExtension>(ExtensionTypeEnum.RAG)\nif (!ext?.ingestAttachments) throw new Error('RAG extension with ingestAttachments must be registered before uploading documents')","typeGuard":"const hasRagIngest = (): boolean =>\n  !!ExtensionManager.getInstance().get<RAGExtension>(ExtensionTypeEnum.RAG)?.ingestAttachments","tryCatchPattern":"try {\n  await uploads.ingestFileAttachment(threadId, att)\n} catch (e) {\n  if (e instanceof Error && e.message === 'RAG extension not available') {\n    showExtensionSetupPrompt('Install/enable the RAG extension to upload documents')\n    return\n  }\n  throw e\n}","preventionTips":["Register the RAG extension during app bootstrap before enabling upload features","Gate document-upload UI on a capability check (ext?.ingestAttachments)","Pin @janhq/core versions between app and extensions and review its changelog for RAGExtension interface changes"],"tags":["extension","rag","missing-dependency"],"backgroundTag":"missing-dependency","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"}