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
- 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
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
- 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
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
- File not found: ${key}
- Source not found: ${sourceKey}
- DESTINATION_EXISTS
- Generation log object key exceeds COS limit
- Invalid generation log key
AI-assisted analysis of TencentCloud/TencentDB-Agent-Memory@3efcd317b8 (2026-09-01).
Data as JSON: /api/errors/4f30281d28a73d03.
Report an issue: GitHub.