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

The orch-review workflow is a fail-closed review gate: it validates its args payload before approving anything. This throw fires when args is a string that cannot be parsed as JSON. The workflow accepts either a plain object or a JSON-encoded string, but a malformed string is rejected outright so the gate never silently approves a payload it could not actually inspect.

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 01e15490f0)

Solutions

  1. Pass a plain JS object instead of a string: orchReview({ diff, changedFiles }).
  2. If you must pass a string, build it with JSON.stringify(payload) so it is always valid JSON.
  3. Pre-validate the string with JSON.parse in your caller and surface the parse error before invoking the workflow.

Example fix

// before
orchReview('{diff: "+++", changedFiles: ["a.js"]}'); // invalid JSON keys

// after
orchReview({ diff: '+++', changedFiles: ['a.js'] }); // pass an object
Defensive patterns

Strategy: validation

Validate before calling

// Pre-validate a string payload before calling the workflow.
let payload = args;
if (typeof payload === 'string') {
  try { payload = JSON.parse(payload); }
  catch { throw new Error('args is not valid JSON — pass an object or JSON.stringify first'); }
}

Type guard

// Ensure args is a plain object before invoking the review gate.
function isPlainObject(v) {
  return typeof v === 'object' && v !== null && !Array.isArray(v);
}

Try / catch

try {
  orchReview(args);
} catch (e) {
  if (e.message.startsWith('orch-review: args must be an object or valid JSON')) {
    // Rebuild the payload as a guaranteed-valid object and retry, or surface to caller.
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling orchReview("{diff: '...'}") (unquoted keys = invalid JSON); orchReview("diff: ...") (plain text, not JSON); orchReview("[broken") (truncated); shell quoting mangles a stringified payload into invalid JSON.

Common situations: Caller hand-builds a JSON string instead of JSON.stringify-ing an object; a shell heredoc or variable expansion breaks the JSON; a templating layer emits JS-object literal syntax instead of JSON.

Related errors


AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13). Data as JSON: /api/errors/b53a66d582f3d4ba. Report an issue: GitHub.