janhq/jan · error · Error
File '${file.name}' has already been attached to this projec
Error message
File '${file.name}' has already been attached to this project What it means
Thrown by VectorDBExtension.ingestFileForProject() after the collection is created and existing attachments are listed, when an attachment with the same name AND path already exists. Duplicate detection is by (name, path) pair, so a renamed copy or a same-name file from a different path is allowed. Note the collection is created before the duplicate check, so a rejected ingest still leaves the collection in place.
Source
Thrown at extensions/vector-db-extension/src/index.ts:107
const text = await ragApi.parseDocument(file.path, file.type || 'application/octet-stream')
const chunks = await this.chunkText(text, opts.chunkSize, opts.chunkOverlap)
// Get embeddings to determine dimension - use a default if no chunks
let dimension = 0
if (chunks.length > 0) {
const embeddings = await this.embedTexts(chunks)
dimension = embeddings[0]?.length || 0
}
// Ensure collection exists (use default dimension 384 if no embeddings yet)
const collectionDimension = dimension > 0 ? dimension : 384
await this.createCollectionForProject(projectId, collectionDimension)
// Now check for duplicates
const existingFiles = await vecdb.listAttachments(this.collectionForProject(projectId)).catch(() => [])
const duplicate = existingFiles.find((f: any) => f.name === file.name && f.path === file.path)
if (duplicate) {
throw new Error(`File '${file.name}' has already been attached to this project`)
}
if (!chunks.length) {
const fi = await vecdb.createFile(this.collectionForProject(projectId), file)
return fi
}
// Re-embed if we got dimension from createCollection
const embeddings = await this.embedTexts(chunks)
const finalDimension = embeddings[0]?.length || 0
if (finalDimension <= 0) throw new Error('Embedding dimension not available')
// Ensure collection has correct dimension
if (finalDimension !== collectionDimension) {
await this.deleteCollectionForProject(projectId)
await this.createCollectionForProject(projectId, finalDimension)
}
View on GitHub (pinned to fad3f12a14)
Solutions
- Check existing attachments via listAttachmentsForProject before ingesting and skip duplicates.
- Delete the existing attachment (deleteFileForProject) before re-ingesting if you want a fresh copy.
- Dedupe the file list by (name, path) before calling ingest.
- Treat this error as a no-op success if idempotent re-ingest is desired.
Example fix
// before await vecdbExt.ingestFileForProject(projectId, file, opts) // after const existing = await vecdbExt.listAttachmentsForProject(projectId) const dup = existing.find((f) => f.name === file.name && f.path === file.path) if (dup) return dup // idempotent: return the existing record await vecdbExt.ingestFileForProject(projectId, file, opts)
Defensive patterns
Strategy: validation
Validate before calling
const existing = await vecdbExt.listAttachmentsForProject(projectId)
const isDup = existing.some((f) => f.name === file.name && f.path === file.path)
if (isDup) {
// skip, or deleteFileForProject first to refresh
} Try / catch
try {
await vecdbExt.ingestFileForProject(projectId, file, opts)
} catch (e) {
if (e instanceof Error && e.message.includes('already been attached')) return // idempotent
throw e
} Prevention
- Dedupe the upload list by (name, path) before ingesting.
- Track attached files in UI state to prevent re-attach.
- Delete the old record before re-ingesting if a refresh is intended.
When it happens
Trigger: Calling ingestFileForProject twice with the same file; re-running ingestion after a partial failure that already created the attachment record; a retry loop that does not dedupe.
Common situations: User re-attaches the same document; automation re-ingests a project on every run; a resume-after-crash retries the already-recorded file.
Related errors
- File '${file.name}' has already been attached to this thread
- Vector DB extension does not support project-level ingestion
- Embedding dimension not available
- Model ${modelId} already exists
- Model already loaded!!
AI-assisted analysis of janhq/jan@fad3f12a14 (2026-08-12).
Data as JSON: /api/errors/f8d3d00e34c46d7c.
Report an issue: GitHub.