TencentCloud/TencentDB-Agent-Memory · error
DESTINATION_EXISTS
DESTINATION_EXISTS
Error message
DESTINATION_EXISTS: ${dstPrefix} What it means
copyTree refuses to overwrite an existing destination. Unless opts.overwrite is true, it lists the destination prefix and throws DESTINATION_EXISTS if any file objects already exist there, protecting callers from clobbering data (e.g. backups).
Source
Thrown at MemoryCore/src/core/storage/adapter.ts:275
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;
if (rel.startsWith(srcNorm)) rel = rel.slice(srcNorm.length);
else if (rel === srcPrefix) rel = "";
const dstKey = `${dstNorm}${rel}`;
const obj = await this.backend.getObject(entry.key);
if (!obj) continue;
await this.backend.putObject(dstKey, obj.content, {
contentType: obj.contentType,
metadata: obj.metadata,View on GitHub (pinned to 3efcd317b8)
Solutions
- Pass { overwrite: true } if replacing the destination is intended
- Use a unique destination prefix (timestamp/uuid suffix) per copy
- Delete or archive the existing destination prefix before copying
- Catch DESTINATION_EXISTS and prompt the user / choose a new destination
Example fix
// before
await adapter.copyTree('ws/a', 'backups/a', {}); // throws if backups/a has files
// after
await adapter.copyTree('ws/a', `backups/a-${Date.now()}`, {}); Defensive patterns
Strategy: validation
Validate before calling
const dstEntries = await adapter.list(dstPrefix);
if (dstEntries.some((e) => !e.isDirectory) && !opts.overwrite) {
dstPrefix = `${dstPrefix}-${Date.now()}`; // pick a unique destination up front
} Try / catch
try {
await adapter.copyTree(src, dst, { overwrite: false });
} catch (e) {
if (String(e.message).startsWith('DESTINATION_EXISTS:')) {
await adapter.copyTree(src, dst, { overwrite: true }); // explicit overwrite decision
} else throw e;
} Prevention
- Always generate unique destination prefixes (uuid/timestamp) for snapshots
- Be explicit about overwrite intent — pass overwrite: true rather than relying on empty destinations
- Clean up partial copies after failed operations to avoid phantom destinations
- Expose an overwrite flag in user-facing copy commands instead of failing silently
When it happens
Trigger: Calling copyTree(srcPrefix, dstPrefix) without opts.overwrite when the destination prefix already contains one or more non-directory objects.
Common situations: Running a backup/snapshot twice with the same destination name; a previous partial copy left objects behind; timestamped destination not actually unique (same second/collision); retry after a failed copy without cleanup.
Related errors
- STORAGE_NOT_FOUND
- Generation log object key exceeds COS limit
- Invalid generation log key
- Invalid generation log cursor
- Invalid scoped storage key: ${JSON.stringify(key)}
AI-assisted analysis of TencentCloud/TencentDB-Agent-Memory@3efcd317b8 (2026-09-01).
Data as JSON: /api/errors/64edcd314e87fcec.
Report an issue: GitHub.