TencentCloud/TencentDB-Agent-Memory · error
Storage key must be relative, got absolute
Error message
Storage key must be relative, got absolute: ${key} What it means
LocalStorageBackend.resolvePath() maps storage object keys to file paths under a configured rootDir. As part of a path-traversal security fix (CR-6), it rejects any key that starts with '/' or '\' because such keys are absolute paths and could target arbitrary filesystem locations instead of staying inside rootDir. Keys must be relative path segments joined under the backend root.
Solutions
- Strip leading '/' or '\\' (and collapse duplicate separators) from the key before passing it to the backend.
- Fix the source of the key (config or user input) so it is stored as a relative path segment; validate at ingestion.
- If an absolute path is genuinely needed, configure the backend's rootDir to that location and use a relative key instead.
Example fix
// before
const key = `${sessionKey}/memory.json`; // sessionKey = "/data/instances/abc"
await storage.putObject(key, data);
// after
const relKey = sessionKey.replace(/^[\\/]+/, "");
const key = `${relKey}/memory.json`;
await storage.putObject(key, data); Defensive patterns
Strategy: validation
Validate before calling
function isSafeRelativeKey(key: string): boolean {
return typeof key === "string" && key.length > 0 && !key.startsWith("/") && !key.startsWith("\\") && !key.includes("\0");
}
if (!isSafeRelativeKey(key)) throw new Error(`key must be relative: ${key}`); Type guard
function isRelativeKey(key: unknown): key is string {
return typeof key === "string" && key.length > 0 && !key.startsWith("/") && !key.startsWith("\\");
} Try / catch
try {
await storage.putObject(key, data);
} catch (e) {
if (e instanceof Error && e.message.startsWith("Storage key must be relative")) {
key = key.replace(/^[\\/]+/, "");
await storage.putObject(key, data);
} else throw e;
} Prevention
- Always build keys from sanitized relative segments; strip leading slashes from user input at ingestion.
- Validate config fields like sessionKey/instanceId against /^[^\\/]/ before they reach storage keys.
- Add a unit test asserting keys beginning with '/' or '\\' are rejected.
When it happens
Trigger: Calling putObject/getObject/appendObject/list (any method that calls resolvePath) with a key that begins with '/' (POSIX absolute, e.g. '/etc/passwd') or '\\' (Windows absolute, e.g. '\\\\server\\share\\file'). Commonly produced by joining user-controlled fields like instanceId, sceneName or sessionKey that already contain a leading slash into the key template.
Common situations: A config value such as sessionKey or instanceId was set to an absolute path by mistake; code migrated from an API that accepted absolute paths; string concatenation like root + '/' + key where key already starts with '/'; on Windows, UNC paths ('\\\\server\\share') pasted into a config field.
Related errors
- Path traversal rejected in scoped storage key
- Path traversal rejected: key
- Invalid generation log key
- invalid team_id for template path
- Generation log object key exceeds COS limit
AI-assisted analysis of TencentCloud/TencentDB-Agent-Memory@3efcd317b8 (2026-09-01).
Data as JSON: /api/errors/1376fe8affc4cc09.
Report an issue: GitHub.
Appendix: source
Thrown at MemoryCore/src/core/storage/local-backend.ts:69
* rootDir). Affects standalone mode where user-controllable fields like
* instanceId / sceneName / sessionKey end up in the key.
*
* Rejected:
* - Empty key
* - Keys containing NUL (\0) — POSIX/Linux path terminator, can confuse
* downstream tooling (sqlite, file managers).
* - Keys with leading "/" or "\" (absolute paths).
* - Keys whose resolved path falls outside rootDir (../ traversal).
*/
private resolvePath(key: string): string {
if (!key || typeof key !== "string") {
throw new Error(`Invalid storage key: ${JSON.stringify(key)}`);
}
if (key.includes("\0")) {
throw new Error("Storage key must not contain NUL character");
}
if (key.startsWith("/") || key.startsWith("\\")) {
throw new Error(`Storage key must be relative, got absolute: ${key}`);
}
// Normalize key separators to OS path separators
const normalized = key.split("/").join(sep);
// Compute the absolute resolved path; resolve() collapses ".." segments.
const absRoot = resolve(this.rootDir);
const absResolved = resolve(absRoot, normalized);
// Ensure the resolved path stays inside rootDir. Append sep so that
// a key like "../rootDir2/foo" (which resolves to a sibling directory
// whose name happens to start with rootDir's name) is also rejected.
const rootWithSep = absRoot.endsWith(sep) ? absRoot : absRoot + sep;
if (absResolved !== absRoot && !absResolved.startsWith(rootWithSep)) {
throw new Error(`Path traversal rejected: key "${key}" escapes rootDir`);
}
return absResolved;View on GitHub (pinned to 3efcd317b8)