TencentCloud/TencentDB-Agent-Memory · error

STORAGE_NOT_FOUND

STORAGE_NOT_FOUND

Error message

STORAGE_NOT_FOUND: ${srcPrefix}

What it means

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.

Source

Thrown at MemoryCore/src/core/storage/adapter.ts:266

   *
   * 在 Phase 5 之后被 skill-versioning 使用:每次 owner 改动触发新版本时,
   * 把上一版本目录拷贝到新版本目录,再应用本次资源变更(write/remove)。
   */
  async copyTree(
    srcPrefix: string,
    dstPrefix: string,
    opts: { overwrite?: boolean } = {},
  ): Promise<void> {
    const srcEntries = await this.backend.listObjects(srcPrefix, {
      maxKeys: 100_000,
      recursive: true,
    });

    // src 下没有任何对象 → 视为不存在
    const srcFiles = srcEntries.entries.filter((e) => !e.isDirectory);
    const srcExists = await this.backend.exists(srcPrefix);
    if (srcFiles.length === 0 && !srcExists) {
      throw new Error(`STORAGE_NOT_FOUND: ${srcPrefix}`);
    }

    if (!opts.overwrite) {
      const dstEntries = await this.backend.listObjects(dstPrefix, {
        maxKeys: 1000,
        recursive: true,
      });
      if (dstEntries.entries.some((e) => !e.isDirectory)) {
        throw new Error(`DESTINATION_EXISTS: ${dstPrefix}`);
      }
    }

    const srcNorm = srcPrefix.endsWith("/") ? srcPrefix : srcPrefix + "/";
    const dstNorm = dstPrefix.endsWith("/") ? dstPrefix : dstPrefix + "/";

    for (const entry of srcFiles) {
      // 计算相对路径
      let rel = entry.key;

View on GitHub (pinned to 3efcd317b8)

Solutions

  1. Verify the source prefix exists and contains objects (listObjects) before copyTree
  2. Fix the srcPrefix — check scope prefix, trailing slash, and case
  3. Skip the copy when the source is legitimately empty (guard with listObjects/exists)
  4. Seed the source tree with default content if absence is unexpected

Example fix

// before
await adapter.copyTree('workspaces/a', 'backups/a', {});
// after
if (!(await adapter.exists('workspaces/a'))) return; // nothing to copy
await adapter.copyTree('workspaces/a', 'backups/a', {});
Defensive patterns

Strategy: validation

Validate before calling

const entries = await adapter.list?.(srcPrefix) ?? (await adapter.exists(srcPrefix));
const hasFiles = Array.isArray(entries) ? entries.some((e) => !e.isDirectory) : entries;
if (!hasFiles) return; // nothing to copy — skip instead of throwing

Try / catch

try {
  await adapter.copyTree(src, dst, opts);
} catch (e) {
  if (String(e.message).startsWith('STORAGE_NOT_FOUND:')) {
    logger.warn(`copyTree skipped, source missing: ${src}`);
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of TencentCloud/TencentDB-Agent-Memory@3efcd317b8 (2026-09-01). Data as JSON: /api/errors/4f30281d28a73d03. Report an issue: GitHub.