affaan-m/ECC · error · Error
No trusted boundary policy is configured for memory scope "$
Error message
No trusted boundary policy is configured for memory scope "${scope}". What it means
Thrown by assertMemoryRootSafe() when the hidden Symbol-keyed boundary map (roots[VAULT_ROOT_BOUNDARIES]) does not contain a non-empty string for the requested scope. The boundary is the trusted ancestor directory that the root path must stay inside (defense against symlink escapes). resolveVaultRoots() installs this Symbol property non-enumerably; a hand-built or stripped roots object will not have it.
Source
Thrown at scripts/lib/memory-vault.js:107
}),
enumerable: false,
configurable: false,
writable: false,
});
return Object.freeze(roots);
}
function assertMemoryRootSafe(roots, scope) {
if (!roots || typeof roots !== 'object' || Array.isArray(roots)) {
throw new Error('Memory roots must include a trusted boundary policy.');
}
const root = roots[scope];
if (typeof root !== 'string' || root.length === 0) {
throw new Error(`No memory root is configured for scope "${scope}".`);
}
const boundary = roots[VAULT_ROOT_BOUNDARIES]?.[scope];
if (typeof boundary !== 'string' || boundary.length === 0) {
throw new Error(`No trusted boundary policy is configured for memory scope "${scope}".`);
}
assertWithinTrustedRoot(root, boundary, 'access memory through a symlink');
if (fs.existsSync(root) && fs.lstatSync(root).isSymbolicLink()) {
throw new Error(`Refusing to access memory through symlink root: ${root}`);
}
return root;
}
function assertMemoryDirectorySafe(directory, root) {
assertWithinTrustedRoot(directory, root, 'access memory directory');
if (fs.existsSync(directory) && fs.lstatSync(directory).isSymbolicLink()) {
throw new Error(`Refusing to access memory through symlink directory: ${directory}`);
}
return directory;
}
function sameFileIdentity(left, right) {
// The inode is the primary identity signal and must always match.View on GitHub (pinned to 01e15490f0)
Solutions
- Always use resolveVaultRoots() to produce roots — it installs the Symbol boundary map correctly.
- Never clone roots via spread, Object.assign, or JSON round-trip; pass the original frozen object.
- If you must override a path, call resolveVaultRoots({ ECC_MEMORY_PROJECT_ROOT, ECC_MEMORY_USER_ROOT }) again.
- Treat the boundary map as load-bearing security state — do not strip non-enumerable keys.
Example fix
// before — drops the Symbol boundary map
const roots = { ...resolveVaultRoots(), project: '/override' };
saveMemory(input, { roots });
// after — re-resolve with env override so the boundary map survives
const roots = resolveVaultRoots({ ECC_MEMORY_PROJECT_ROOT: '/override' });
saveMemory(input, { roots }); Defensive patterns
Strategy: validation
Validate before calling
// roots must come from resolveVaultRoots(); never spread or JSON-round-trip
if (!options.roots) {
options.roots = resolveVaultRoots({
ECC_MEMORY_PROJECT_ROOT: process.env.ECC_MEMORY_PROJECT_ROOT,
ECC_MEMORY_USER_ROOT: process.env.ECC_MEMORY_USER_ROOT,
});
} Prevention
- Never clone roots via {...roots}, Object.assign({}, roots), or JSON.parse(JSON.stringify(roots)) — Symbol keys are dropped.
- Re-resolve roots with the appropriate env var when you need to override a path.
- Treat the boundary map as load-bearing security state; do not strip non-enumerable properties.
When it happens
Trigger: A test or wrapper that built roots = { project: '/a', team: '/b', user: '/c' } literally without the Symbol boundary map. JSON.parse(JSON.stringify(roots)) which drops the Symbol property. Object.assign({}, roots) which copies only enumerable keys. Spread {...roots} which also omits non-enumerable Symbol keys.
Common situations: Test fixture that hand-constructed a roots object. Wrapper that tried to 'clone and modify' roots via spread. Debug logging that serialized and re-parsed roots. Custom resolver that returned a plain object without calling the internal defineProperty for the boundary Symbol.
Related errors
- ${label} must not contain control or bidirectional formattin
- memory body must not contain unsafe control or bidirectional
- Memory roots must include a trusted boundary policy.
- No memory root is configured for scope "${scope}".
- ${label} must be a regular, non-symlink file.
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/6df8ad946346e872.
Report an issue: GitHub.