affaan-m/ECC · error · Error
Unknown argument
Error message
Unknown argument: ${arg} What it means
Each scope root must be paired with a trusted boundary policy string under roots[VAULT_ROOT_BOUNDARIES][scope]; that boundary defines the trusted filesystem region the root must stay inside. If the boundary is missing, empty, or not a string, assertMemoryRootSafe throws this error. The library refuses to operate without an explicit trust boundary so symlink and path-escape attacks cannot bypass containment.
Solutions
- Add a trusted boundary path for the scope under roots[VAULT_ROOT_BOUNDARIES][scope] (the boundary must contain the scope root).
- Set the boundary to the same directory as the root (or a parent of it) if the whole root directory is trusted.
- Validate the roots object on startup with a check that iterates all scopes and asserts each has a non-empty boundary.
- Regenerate the config from the installer/template that emits both roots and boundaries together.
Example fix
// before
const roots = { project: '/vault/project' };
// after
const roots = {
project: '/vault/project',
[VAULT_ROOT_BOUNDARIES]: { project: '/vault/project' }
}; Defensive patterns
Strategy: validation
Validate before calling
const VAULT_ROOT_BOUNDARIES = '__boundaries'; // match the library's key
function assertBoundariesPresent(roots, scopes) {
for (const scope of scopes) {
const b = roots?.[VAULT_ROOT_BOUNDARIES]?.[scope];
if (typeof b !== 'string' || b.length === 0) {
throw new Error(`Scope "${scope}" is missing its trusted boundary policy in ${VAULT_ROOT_BOUNDARIES}.`);
}
}
} Type guard
const hasBoundary = (roots, scope) => typeof roots?.[VAULT_ROOT_BOUNDARIES]?.[scope] === 'string' && roots[VAULT_ROOT_BOUNDARIES][scope].length > 0;
Try / catch
try {
const root = resolveMemoryRoot(roots, scope);
} catch (err) {
if (err.message.includes('trusted boundary policy is configured')) {
throw new Error(`Add ${scope} to the boundary map in your memory roots config.`);
}
throw err;
} Prevention
- Always add the root and its boundary entry together — never edit one without the other.
- Generate roots config from a template/installer that emits both maps.
- Validate every configured scope has a boundary at startup.
- Document the boundary requirement wherever root configuration is documented.
When it happens
Trigger: Providing a roots object that maps scope -> path but omits the corresponding entry in the VAULT_ROOT_BOUNDARIES map, sets it to '' or null, or builds the boundaries object dynamically and the scope key never got inserted.
Common situations: Hand-writing the roots config and adding a new scope path without adding its boundary entry; a migration that renamed VAULT_ROOT_BOUNDARIES or restructured the config; copying a scope entry without its boundary counterpart; programmatically generated config where a loop skipped one scope.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- ECC_PROJECT_DIR must be a child path within /workspace.
- Invalid ECC repo root: missing package.json at
- must not contain control or bidirectional formatting…
- memory body must not contain unsafe control or…
- Memory destination changed while it was being created.
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/926789182a1251fe.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/auto-update.js:48
};
for (let index = 0; index < args.length; index += 1) {
const arg = args[index];
if (arg === '--target') {
parsed.targets.push(args[index + 1] || null);
index += 1;
} else if (arg === '--repo-root') {
parsed.repoRoot = args[index + 1] || null;
index += 1;
} else if (arg === '--dry-run') {
parsed.dryRun = true;
} else if (arg === '--json') {
parsed.json = true;
} else if (arg === '--help' || arg === '-h') {
parsed.help = true;
} else {
throw new Error(`Unknown argument: ${arg}`);
}
}
return parsed;
}
function deriveRepoRootFromState(state) {
const operations = Array.isArray(state && state.operations) ? state.operations : [];
for (const operation of operations) {
if (typeof operation.sourcePath !== 'string' || !operation.sourcePath.trim()) {
continue;
}
if (typeof operation.sourceRelativePath !== 'string' || !operation.sourceRelativePath.trim()) {
continue;
}
View on GitHub (pinned to 8321021c54)