{"record":{"id":"a5c9078504931561","repo":"TencentCloud/TencentDB-Agent-Memory","slug":"source-not-found-sourcekey","errorCode":null,"errorMessage":"Source not found: ${sourceKey}","messagePattern":"Source not found: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"MemoryCore/src/core/storage/adapter.ts","lineNumber":216,"sourceCode":"    return {\n      key,\n      size: obj.size ?? obj.content.length,\n      lastModified,\n      createdAt: lastModified,\n    };\n  }\n\n  // ── fs.rename replacement ──\n\n  async rename(sourceKey: string, destKey: string): Promise<void> {\n    // CR-8 partial fix (2026-05-19): preserve contentType + metadata across rename.\n    // The 3-step (get → put → delete) is still NOT atomic; if the process is killed\n    // between put and delete, both source and dest will exist (data duplication).\n    // A complete fix requires a native renameObject in IStorageBackend (using\n    // POSIX fs.rename for local + COS x-cos-copy-source for remote). Tracked as\n    // long-term work — see audit report H-6 (persona.md backup rotation).\n    const obj = await this.backend.getObject(sourceKey);\n    if (!obj) throw new Error(`Source not found: ${sourceKey}`);\n    await this.backend.putObject(destKey, obj.content, {\n      contentType: obj.contentType,\n      metadata: obj.metadata,\n    });\n    await this.backend.deleteObject(sourceKey);\n  }\n\n  // ── fs.copyFile replacement ──\n\n  async copyFile(sourceKey: string, destKey: string): Promise<void> {\n    // CR-8 partial fix (2026-05-19): preserve contentType + metadata across copy.\n    const obj = await this.backend.getObject(sourceKey);\n    if (!obj) throw new Error(`Source not found: ${sourceKey}`);\n    await this.backend.putObject(destKey, obj.content, {\n      contentType: obj.contentType,\n      metadata: obj.metadata,\n    });\n  }","sourceCodeStart":198,"sourceCodeEnd":234,"githubUrl":"https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/3efcd317b84146d6a08518ac0f7ee7c8a8d200ec/MemoryCore/src/core/storage/adapter.ts#L198-L234","documentation":"ScopedStorageAdapter.rename implements rename as a non-atomic get → put → delete. It throws this error when the source object does not exist in the backend. The code comments note a native renameObject on IStorageBackend is required for true atomicity (tracked long-term, audit H-6).","triggerScenarios":"Calling rename(sourceKey, destKey) — directly or indirectly via atomicWriteJson — when getObject(sourceKey) returns null, i.e. the source object was never written or was already deleted.","commonSituations":"atomicWriteJson on a path whose current file doesn't exist yet when expecting one; racing deletes from another worker; key mismatch (case, prefix, extension) between write and rename.","solutions":["Ensure the source object exists before renaming (write it first or check exists())","If the intent is 'create or replace', use putObject on destKey instead of rename","Guard with exists() and skip or create the source as appropriate","Serialize concurrent operations touching the same key to avoid a delete/rename race"],"exampleFix":"// before\nawait adapter.rename(tmpKey, finalKey); // throws if tmpKey missing\n// after\nif (await adapter.exists(tmpKey)) await adapter.rename(tmpKey, finalKey);\nelse await adapter.putObject(finalKey, defaultContent);","handlingStrategy":"validation","validationCode":"if (!(await adapter.exists(sourceKey))) {\n  throw new NotFoundError(`cannot rename missing object: ${sourceKey}`);\n}\nawait adapter.rename(sourceKey, destKey);","typeGuard":null,"tryCatchPattern":"try {\n  await adapter.rename(src, dst);\n} catch (e) {\n  if (String(e.message).startsWith('Source not found:')) {\n    await adapter.putObject(dst, defaultContent); // create-or-replace semantics\n  } else throw e;\n}","preventionTips":["Remember rename is get→put→delete, not atomic — avoid concurrent renames of the same key","For 'replace' semantics use putObject directly instead of rename","For 'move' semantics check existence first and define absent-source behavior","Write the temp file immediately before renaming in write-temp patterns"],"tags":["storage","file-not-found","rename","atomicity"],"backgroundTag":"file-not-found","analyzedSha":"3efcd317b84146d6a08518ac0f7ee7c8a8d200ec","analyzedAt":"2026-09-01T05:44:22.276Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}