{"record":{"id":"89f8494318308a85","repo":"TencentCloud/TencentDB-Agent-Memory","slug":"file-not-found-key","errorCode":null,"errorMessage":"File not found: ${key}","messagePattern":"File not found: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"MemoryCore/src/core/storage/adapter.ts","lineNumber":99,"sourceCode":"  return new StorageAdapter(new ScopedStorageBackend(base.getBackend(), prefix));\n}\n\nexport class StorageAdapter {\n  constructor(private backend: IStorageBackend) {}\n\n  get type() { return this.backend.type; }\n\n  // ── fs.readFile replacement ──\n\n  async readFile(key: string): Promise<string | null> {\n    const obj = await this.backend.getObject(key);\n    if (!obj) return null;\n    return obj.content.toString(\"utf-8\");\n  }\n\n  async readFileOrThrow(key: string): Promise<string> {\n    const content = await this.readFile(key);\n    if (content === null) throw new Error(`File not found: ${key}`);\n    return content;\n  }\n\n  async readFileBuffer(key: string): Promise<Buffer | null> {\n    const obj = await this.backend.getObject(key);\n    if (!obj) return null;\n    return obj.content;\n  }\n\n  // ── fs.writeFile replacement ──\n\n  async writeFile(key: string, content: string | Buffer): Promise<void> {\n    return this.backend.putObject(key, content);\n  }\n\n  // ── fs.appendFile replacement — atomic via backend.appendObject (CR-1 fix) ──\n\n  /**","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/3efcd317b84146d6a08518ac0f7ee7c8a8d200ec/MemoryCore/src/core/storage/adapter.ts#L81-L117","documentation":"readFileOrThrow is the strict variant of readFile: readFile returns null for a missing object, while readFileOrThrow converts that null into a thrown Error with the key in the message. It exists so callers that require the file can avoid null-check boilerplate.","triggerScenarios":"Calling readFileOrThrow(key) when no object exists at that (already prefixed) key in the storage backend.","commonSituations":"Reading a config or state file before it was ever written; a typo or case mismatch in the key; the object was deleted by another process; using the raw key without the adapter's scoping prefix on a raw backend.","solutions":["Check existence first with adapter.exists(key) or use readFile and handle null","Fix the key — verify exact spelling/case and that it is relative to the adapter's scope","Create/initialize the object (write a default) on first access if absence is expected","Handle the error and fall back to a default value in the caller"],"exampleFix":"// before\nconst cfg = await adapter.readFileOrThrow('config.json');\n// after\nconst cfg = (await adapter.readFile('config.json')) ?? JSON.stringify(DEFAULT_CONFIG);","handlingStrategy":"try-catch","validationCode":"if (!(await adapter.exists(key))) {\n  return DEFAULT_CONTENT; // or throw a domain-level NotFound\n}","typeGuard":null,"tryCatchPattern":"try {\n  content = await adapter.readFileOrThrow(key);\n} catch (e) {\n  if (String(e.message).startsWith('File not found:')) {\n    content = await initializeDefault(key); // create default on first access\n  } else throw e;\n}","preventionTips":["Prefer readFile (null-returning) when absence is an expected state","Use readFileOrThrow only for files that must exist (invariants/config)","Verify key spelling, case, and scope prefix when debugging","Write defaults at first boot so required keys always exist"],"tags":["storage","file-not-found","missing-file"],"backgroundTag":"file-not-found","analyzedSha":"3efcd317b84146d6a08518ac0f7ee7c8a8d200ec","analyzedAt":"2026-09-01T05:44:22.276Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}