affaan-m/ECC · error · Error
ECC_PROJECT_DIR must be a child path within /workspace.
Error message
ECC_PROJECT_DIR must be a child path within /workspace.
What it means
assertMemoryRootSafe validates the roots configuration object before any memory scope path is resolved. The roots argument must be a non-null, non-array object that also carries a trusted boundary policy map (under the VAULT_ROOT_BOUNDARIES key). If roots is not such an object, this error is thrown immediately. It is the coarsest-grained guard in the memory-vault path-safety chain.
Solutions
- Pass the complete roots object (scope paths plus the trusted boundary policy map) instead of null/undefined/array.
- Fix the config loader so the memory roots section is actually populated before calling the vault API.
- Check that you are not filtering/mapping the roots object into an array upstream.
- Add a startup validation that the roots config parses to the expected shape before invoking memory operations.
Example fix
// before
resolveMemoryRoot(null, 'project');
// after
const roots = loadMemoryRootsConfig(); // { project: '/path', ..., [VAULT_ROOT_BOUNDARIES]: {...} }
resolveMemoryRoot(roots, 'project'); Defensive patterns
Strategy: validation
Validate before calling
function assertValidRoots(roots) {
if (!roots || typeof roots !== 'object' || Array.isArray(roots)) {
throw new TypeError('Memory roots config must be a plain object with scope paths and a trusted boundary policy.');
}
} Type guard
const isRootsConfig = (v) => !!v && typeof v === 'object' && !Array.isArray(v);
Try / catch
try {
const root = resolveMemoryRoot(roots, scope);
} catch (err) {
if (err.message.includes('trusted boundary policy')) {
throw new Error(`Memory roots config invalid — check loadMemoryRootsConfig output: ${err.message}`);
}
throw err;
} Prevention
- Validate the roots config shape once at startup, before any memory operation.
- Never pass arrays or partial stubs where the full roots object is expected.
- Fail fast with a clear message if config loading yields null/undefined.
- Type-check config-loading functions so they cannot silently return undefined.
When it happens
Trigger: Calling the root accessor (via memory / saveMemory paths) with roots = null, undefined, a string, a number, or an Array instead of the expected plain object containing scope roots plus a boundaries map. Typically caused by passing a misloaded or absent config object.
Common situations: Configuration file failed to load so the default config value is undefined; a caller passed just the list of root paths (an array) instead of the full roots object; a refactor renamed the boundaries key so the validated object no longer matches; unit tests passing a partial stub.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- message
- no tier ' ' for slot ' '; have
- Refusing to ' ': no trusted install root resolved.
- Unknown argument
- Announcements discussion category is required
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/b53a66d582f3d4ba.
Report an issue: GitHub.
Appendix: source
Thrown at docker/plugin-setup/resolve-project-dir.js:20
'use strict';
const path = require('path');
const WORKSPACE_ROOT = '/workspace';
function resolveProjectDir(candidate) {
if (
typeof candidate !== 'string'
|| !path.posix.isAbsolute(candidate)
|| /[\0\r\n]/.test(candidate)
) {
throw new Error('ECC_PROJECT_DIR must be an absolute path within /workspace.');
}
const resolved = path.posix.resolve(candidate);
if (resolved === WORKSPACE_ROOT || !resolved.startsWith(`${WORKSPACE_ROOT}/`)) {
throw new Error('ECC_PROJECT_DIR must be a child path within /workspace.');
}
return resolved;
}
function main() {
try {
process.stdout.write(`${resolveProjectDir(process.argv[2])}\n`);
} catch (error) {
process.stderr.write(`Error: ${error.message}\n`);
process.exitCode = 2;
}
}
if (require.main === module) main();
module.exports = { resolveProjectDir };
View on GitHub (pinned to 8321021c54)