{"record":{"id":"4f30281d28a73d03","repo":"TencentCloud/TencentDB-Agent-Memory","slug":"storage-not-found-4f3028","errorCode":"STORAGE_NOT_FOUND","errorMessage":"STORAGE_NOT_FOUND: ${srcPrefix}","messagePattern":"STORAGE_NOT_FOUND: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"MemoryCore/src/core/storage/adapter.ts","lineNumber":266,"sourceCode":"   *\n   * 在 Phase 5 之后被 skill-versioning 使用：每次 owner 改动触发新版本时，\n   * 把上一版本目录拷贝到新版本目录，再应用本次资源变更（write/remove）。\n   */\n  async copyTree(\n    srcPrefix: string,\n    dstPrefix: string,\n    opts: { overwrite?: boolean } = {},\n  ): Promise<void> {\n    const srcEntries = await this.backend.listObjects(srcPrefix, {\n      maxKeys: 100_000,\n      recursive: true,\n    });\n\n    // src 下没有任何对象 → 视为不存在\n    const srcFiles = srcEntries.entries.filter((e) => !e.isDirectory);\n    const srcExists = await this.backend.exists(srcPrefix);\n    if (srcFiles.length === 0 && !srcExists) {\n      throw new Error(`STORAGE_NOT_FOUND: ${srcPrefix}`);\n    }\n\n    if (!opts.overwrite) {\n      const dstEntries = await this.backend.listObjects(dstPrefix, {\n        maxKeys: 1000,\n        recursive: true,\n      });\n      if (dstEntries.entries.some((e) => !e.isDirectory)) {\n        throw new Error(`DESTINATION_EXISTS: ${dstPrefix}`);\n      }\n    }\n\n    const srcNorm = srcPrefix.endsWith(\"/\") ? srcPrefix : srcPrefix + \"/\";\n    const dstNorm = dstPrefix.endsWith(\"/\") ? dstPrefix : dstPrefix + \"/\";\n\n    for (const entry of srcFiles) {\n      // 计算相对路径\n      let rel = entry.key;","sourceCodeStart":248,"sourceCodeEnd":284,"githubUrl":"https://github.com/TencentCloud/TencentDB-Agent-Memory/blob/3efcd317b84146d6a08518ac0f7ee7c8a8d200ec/MemoryCore/src/core/storage/adapter.ts#L248-L284","documentation":"copyTree copies every object under a source prefix to a destination prefix. If the source prefix contains no file objects and the backend reports the prefix itself does not exist, the source is treated as nonexistent and STORAGE_NOT_FOUND is thrown with the srcPrefix in the message.","triggerScenarios":"Calling adapter.copyTree(srcPrefix, dstPrefix, opts) when srcPrefix has zero non-directory entries and backend.exists(srcPrefix) is false — e.g. an empty or never-created prefix.","commonSituations":"Copying a user/workspace tree that was never created; typo'd or mis-cased prefix; environment switch (dev data absent in prod backend); bucket/container pointed at the wrong root.","solutions":["Verify the source prefix exists and contains objects (listObjects) before copyTree","Fix the srcPrefix — check scope prefix, trailing slash, and case","Skip the copy when the source is legitimately empty (guard with listObjects/exists)","Seed the source tree with default content if absence is unexpected"],"exampleFix":"// before\nawait adapter.copyTree('workspaces/a', 'backups/a', {});\n// after\nif (!(await adapter.exists('workspaces/a'))) return; // nothing to copy\nawait adapter.copyTree('workspaces/a', 'backups/a', {});","handlingStrategy":"validation","validationCode":"const entries = await adapter.list?.(srcPrefix) ?? (await adapter.exists(srcPrefix));\nconst hasFiles = Array.isArray(entries) ? entries.some((e) => !e.isDirectory) : entries;\nif (!hasFiles) return; // nothing to copy — skip instead of throwing","typeGuard":null,"tryCatchPattern":"try {\n  await adapter.copyTree(src, dst, opts);\n} catch (e) {\n  if (String(e.message).startsWith('STORAGE_NOT_FOUND:')) {\n    logger.warn(`copyTree skipped, source missing: ${src}`);\n    return;\n  }\n  throw e;\n}","preventionTips":["Check source prefix existence with exists()/listObjects before copying","Create the source tree during workspace provisioning so it is never empty","Log srcPrefix/dstPrefix to catch typos and scope-prefix mistakes","Confirm the backend points at the expected environment/bucket root"],"tags":["storage","file-not-found","copy","prefix"],"backgroundTag":"file-not-found","analyzedSha":"3efcd317b84146d6a08518ac0f7ee7c8a8d200ec","analyzedAt":"2026-09-01T05:44:22.276Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}