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

  1. Pass the complete roots object (scope paths plus the trusted boundary policy map) instead of null/undefined/array.
  2. Fix the config loader so the memory roots section is actually populated before calling the vault API.
  3. Check that you are not filtering/mapping the roots object into an array upstream.
  4. 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

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


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)