{"record":{"id":"df0cf7a4e6839ece","repo":"FlowiseAI/Flowise","slug":"metadata-cannot-contain-key-key-as-it-is-reserv","errorCode":null,"errorMessage":"Metadata cannot contain key ${key} as it is reserved for internal use. Restricted keys: [${forbiddenKeys.join(', ')}]","messagePattern":"Metadata cannot contain key (.+?) as it is reserved for internal use\\. Restricted keys: \\[(.+?)\\]","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/components/src/indexing.ts","lineNumber":82,"sourceCode":"\n    metadataHash?: string\n\n    pageContent: string\n\n    metadata: Metadata\n\n    constructor(fields: HashedDocumentArgs) {\n        this.uid = fields.uid\n        this.pageContent = fields.pageContent\n        this.metadata = fields.metadata\n    }\n\n    calculateHashes(): void {\n        const forbiddenKeys = ['hash_', 'content_hash', 'metadata_hash']\n\n        for (const key of forbiddenKeys) {\n            if (key in this.metadata) {\n                throw new Error(\n                    `Metadata cannot contain key ${key} as it is reserved for internal use. Restricted keys: [${forbiddenKeys.join(', ')}]`\n                )\n            }\n        }\n\n        const contentHash = this._hashStringToUUID(this.pageContent)\n\n        try {\n            const metadataHash = this._hashNestedDictToUUID(this.metadata)\n            this.contentHash = contentHash\n            this.metadataHash = metadataHash\n        } catch (e) {\n            throw new Error(`Failed to hash metadata: ${e}. Please use a dict that can be serialized using json.`)\n        }\n\n        this.hash_ = this._hashStringToUUID(this.contentHash + this.metadataHash)\n\n        if (!this.uid) {","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/FlowiseAI/Flowise/blob/abe4a8601a058047b350c260676826e21dd14101/packages/components/src/indexing.ts#L64-L100","documentation":"Thrown by _HashedDocument.calculateHashes() when document metadata contains one of the reserved internal keys: 'hash_', 'content_hash', or 'metadata_hash'. These keys are written by the indexer itself to track document identity; allowing user metadata to set them would collide with the indexing bookkeeping and corrupt deduplication. The check runs before hashes are computed.","triggerScenarios":"Passing a Document to index() whose metadata object has a top-level key named 'hash_', 'content_hash', or 'metadata_hash'. The forbidden loop at lines 80-86 scans the metadata keys and throws on the first collision. This happens during _HashedDocument.fromDocument() → calculateHashes() for every document in every batch.","commonSituations":"User-uploaded documents whose metadata schema happens to use these key names. Migrating from another indexing system that used 'content_hash'. Documents enriched by a pipeline that computes its own hashes and stores them in metadata. A search/indexing feature that lets end-users attach arbitrary metadata.","solutions":["Rename the conflicting key in your metadata before indexing (e.g. 'content_hash' → 'source_content_hash').","Strip reserved keys in a pre-indexing transform: delete doc.metadata.hash_ etc.","Namespace your metadata under a prefix to avoid future collisions (e.g. 'user_hash_').","Validate metadata keys against the reserved list at the document-ingestion boundary so the error never reaches the indexer."],"exampleFix":"// before\nconst docs = [{ pageContent: 'hello', metadata: { content_hash: 'abc', source: 'x' } }]\nawait index({ docsSource: docs, recordManager, vectorStore, options: { cleanup: 'incremental', sourceIdKey: 'source' } })\n\n// after\nconst RESERVED = ['hash_', 'content_hash', 'metadata_hash']\nconst docs = rawDocs.map(d => ({\n  ...d,\n  metadata: Object.fromEntries(Object.entries(d.metadata).filter(([k]) => !RESERVED.includes(k)))\n}))","handlingStrategy":"validation","validationCode":"const RESERVED_META_KEYS = ['hash_', 'content_hash', 'metadata_hash']\n\nfunction stripReservedMetadata<T extends { metadata: Record<string, unknown> }>(doc: T): T {\n  const cleaned = Object.fromEntries(\n    Object.entries(doc.metadata).filter(([k]) => !RESERVED_META_KEYS.includes(k))\n  )\n  return { ...doc, metadata: cleaned }\n}\n\nconst safeDocs = docs.map(stripReservedMetadata)","typeGuard":"function hasReservedMeta(meta: Record<string, unknown>): boolean {\n  return ['hash_', 'content_hash', 'metadata_hash'].some((k) => k in meta)\n}","tryCatchPattern":"try {\n  await index({ docsSource, recordManager, vectorStore, options })\n} catch (e) {\n  if (String(e).includes('reserved for internal use')) {\n    const cleaned = docs.map(stripReservedMetadata)\n    await index({ docsSource: cleaned, recordManager, vectorStore, options })\n  } else throw e\n}","preventionTips":["Validate metadata keys at the document-ingestion boundary.","Namespace custom metadata under a stable prefix to avoid collisions.","Document the reserved-keys list for downstream metadata authors."],"tags":["indexing","metadata","validation","langchain","reserved-keys"],"backgroundTag":null,"analyzedSha":"abe4a8601a058047b350c260676826e21dd14101","analyzedAt":"2026-08-12T16:04:40.823Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}