{"record":{"id":"7dafdcf0241c4c7b","repo":"TencentCloud/TencentDB-Agent-Memory","slug":"invalid-generation-log-key","errorCode":null,"errorMessage":"Invalid generation log key","messagePattern":"Invalid generation log key","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"MemoryCore/src/core/memory-generation-log/store.ts","lineNumber":104,"sourceCode":"    finished_at_ms: Number(match[5]),\n    size,\n    key,\n  };\n}\n\nexport class MemoryGenerationLogStore {\n  private readonly storage: StorageAdapter;\n\n  constructor(storage: StorageAdapter, private readonly instanceId: string) {\n    const safeInstance = safeId(instanceId);\n    this.storage = storage.type === \"local\"\n      ? createScopedStorageAdapter(storage, `instances/${safeInstance}`)\n      : storage;\n  }\n\n  async write(log: MemoryGenerationLog, key: string): Promise<void> {\n    if (!key.startsWith(`${ROOT}/`) || key.includes(\"..\") || key.startsWith(\"/\")) {\n      throw new Error(\"Invalid generation log key\");\n    }\n    await this.storage.getBackend().putObject(key, JSON.stringify(log), {\n      contentType: \"application/json\",\n      metadata: {\n        log_id: log.log_id,\n        layer: log.layer,\n        status: log.status,\n        instance_id: this.instanceId,\n      },\n      tags: {\n        \"tdai-log-type\": \"memory-generation\",\n      },\n    });\n  }\n\n  async getByKey(key: string): Promise<MemoryGenerationLog | null> {\n    if (!key.startsWith(`${ROOT}/`) || key.includes(\"..\") || key.startsWith(\"/\")) return null;\n    const raw = await this.storage.readFile(key);","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/3efcd317b84146d6a08518ac0f7ee7c8a8d200ec/MemoryCore/src/core/memory-generation-log/store.ts#L86-L122","documentation":"MemoryGenerationLogStore.write validates the object key before uploading a generation log: it must start with the expected ROOT prefix, must not contain \"..\", and must not be absolute (start with \"/\"). This prevents writing logs outside the intended prefix (path traversal / namespace escape). A non-conforming key throws \"Invalid generation log key\".","triggerScenarios":"Calling write(log, key) with a key that was not produced by buildGenerationLogIdentity: missing the `${ROOT}/` prefix, containing \"..\" segments, or starting with \"/\"; also happens when a caller hand-builds keys or passes a full URL/absolute path instead of the relative key.","commonSituations":"Caller persisted a key with a different ROOT (ROOT changed across versions) and replays it; manual key construction in scripts; storage instance scoped to instances/<id> while the key is already instance-prefixed causing mismatch; deserialized/parsed keys altered in transit.","solutions":["Always obtain the key from buildGenerationLogIdentity (or the identities returned by the store) rather than constructing it manually","Inspect the failing key: it must start with the ROOT prefix, contain no \"..\", and not begin with \"/\"","If migrating keys from an older version, regenerate them instead of reusing stored keys","Check whether an instance-scoped store (createScopedStorageAdapter) is double-prefixing — pass the unscoped key"],"exampleFix":"// before\nawait store.write(log, `/genlogs/layer=l1/x.json`);\n// after\nconst { key } = buildGenerationLogIdentity({ layer: \"l1\", status: \"ok\", finishedAtMs: Date.now(), anchorMemoryId });\nawait store.write(log, key);","handlingStrategy":"validation","validationCode":"function isValidLogKey(key, root) {\n  return typeof key === \"string\" && key.startsWith(`${root}/`) && !key.includes(\"..\") && !key.startsWith(\"/\");\n}","typeGuard":"function isStoreProducedKey(key, root) {\n  return typeof key === \"string\" && key.startsWith(`${root}/`) && !key.includes(\"..\") && !key.startsWith(\"/\");\n}","tryCatchPattern":"try {\n  await store.write(log, key);\n} catch (e) {\n  if (e.message === \"Invalid generation log key\") {\n    logger.error(`log key rejected: ${key.slice(0, 60)}...; regenerate with buildGenerationLogIdentity`);\n  }\n  throw e;\n}","preventionTips":["Only pass keys returned by buildGenerationLogIdentity into write()","Never hand-build or transform log keys (no leading \"/\", no \"..\", keep the ROOT prefix)","When using an instance-scoped store, pass the original unscoped key"],"tags":["storage","validation","path-traversal","cos"],"backgroundTag":"invalid-object-key","analyzedSha":"3efcd317b84146d6a08518ac0f7ee7c8a8d200ec","analyzedAt":"2026-09-01T05:44:22.276Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}