affaan-m/ECC · error · Error
typing requires a file path
Error message
typing requires a file path
What it means
cmdTyping shows a typing/activity indicator in the canvas chat for the session associated with a plan file. The file path is required to compute the session key; when the positional argument is absent the command throws 'typing requires a file path' before any server contact. The intent is that typing signals are best-effort, but the CLI still refuses to run without knowing which session to signal.
Solutions
- Invoke as `ecc-plan-canvas typing <file> [--state typing|thinking|idle]`, passing the same path used with `open`.
- In scripts, assert the path variable is set before calling the command.
- If the wrapper drops arguments, pass them after `--` or fix the wrapper's argument forwarding.
- Remember typing is fire-and-forget: only the missing-file case throws here; once a path is supplied a dead server just yields status 'no-server'.
Example fix
// before (agent script)
exec(`ecc-plan-canvas typing --state ${state}`);
// after
if (!planPath) throw new Error('planPath required for typing signal');
exec(`ecc-plan-canvas typing ${JSON.stringify(planPath)} --state ${state}`); Defensive patterns
Strategy: validation
Validate before calling
if (!file) throw new Error('typing requires a file path');
if (!fs.existsSync(file)) throw new Error(`plan file not found: ${file}`); Prevention
- Thread the plan path through agent scripts as a single validated variable.
- Pass --state only with values the server understands (typing/thinking/idle).
- Treat typing signals as optional: guard the call site so missing paths degrade to a no-op in non-interactive runs.
When it happens
Trigger: Calling `ecc-plan-canvas typing` without a file positional — omitting the argument entirely, or an agent harness invoking the subcommand with only `--state thinking` and no path.
Common situations: Automating presence indicators from a script where the plan path lives in a variable that is empty; calling the subcommand from the wrong working directory and assuming it infers the file; mixing up argument order so the path lands where a flag expects it and is consumed.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- await requires a file path
- end requires a file path
- An executable is required after --.
- An install config path is required
- At least one --target is required for handoffs.
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/9912c83e6ca0736f.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/plan-canvas.js:302
process.stderr.write('[plan-canvas] waiting for human feedback... leave this running (re-run if interrupted; queued feedback is never lost)\n');
const result = await awaitRequest(port, sessionKeyFor(canonicalizeArtifactPath(file)), timeoutMs);
if (result.status === 'feedback') {
result.next_step = result.sessionEnded
? 'The user sent this feedback and ended the session. Address it and report in chat; do not reopen the canvas uninvited.'
: 'Address the feedback, then run `ecc-plan-canvas await <file> --reply "<what you changed>"` to answer in the canvas and keep listening.';
} else if (result.status === 'ended') {
result.next_step =
result.endedBy === 'user'
? 'The user ended this review. Stop polling and deliver any remaining updates in chat; do not reopen uninvited.'
: 'Session ended. Stop polling.';
}
return result;
}
// Show the human an activity indicator in the canvas chat. Cheap and
// fire-and-forget: a failed signal must never derail the actual work.
async function cmdTyping(file, args, { port }) {
if (!file) throw new Error('typing requires a file path');
const state = valueAfter(args, '--state') || 'typing';
if (!(await healthCheck(port))) return { status: 'no-server' };
const key = sessionKeyFor(canonicalizeArtifactPath(file));
const res = await request(port, 'POST', `/api/session/${key}/typing`, { state });
if (res.statusCode !== 200) throw new Error(res.body.error || `typing failed (HTTP ${res.statusCode})`);
return { status: 'ok', state, presence: res.body.presence };
}
// Report feedback the human sent that no agent has picked up yet. Reads state
// directly so it answers even when the server has idled out.
function cmdPending({ stateDir }) {
const store = createSessionStore({ stateDir });
const waiting = store
.list()
.filter(session => session.status !== 'ended' && session.pending > 0)
.map(session => ({ file: session.file, pending: session.pending, updatedAt: session.updatedAt }));
return {
status: waiting.length ? 'pending' : 'clear',View on GitHub (pinned to 8321021c54)