affaan-m/ECC · warning · Error
typing requires a file path
Error message
typing requires a file path
What it means
Thrown by cmdTyping when the `typing` subcommand is called without a positional file path. The typing command POSTs an activity/presence indicator to a per-file review session (`/api/session/<key>/typing`), so the session key is derived from the file and cannot be omitted. It is a fire-and-forget presence signal meant to cheaply show the agent is working.
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 01e15490f0)
Solutions
- Provide the file whose session you want to signal: `node scripts/plan-canvas.js typing .claude/plans/feature.plan.md`.
- Ensure `open <file>` ran first so a session exists for that key.
- Treat typing failures as non-fatal in the caller — the source comment says a failed signal must never derail the work, so wrap the call and ignore errors when the file is unknown.
Example fix
// before node scripts/plan-canvas.js typing --state thinking // after node scripts/plan-canvas.js typing .claude/plans/feature.plan.md --state thinking
Defensive patterns
Strategy: validation
Validate before calling
function validateTypingFile(file) {
if (typeof file !== 'string' || file.trim() === '') {
throw new Error('cmdTyping: file argument is required');
}
return file;
} Type guard
function isTypingFile(arg) {
return typeof arg === 'string' && arg.length > 0 && !arg.startsWith('--');
} Try / catch
// Presence signals must never break the parent workflow
try {
await cmdTyping(file, args, ctx);
} catch (err) {
console.error(`[plan-canvas] typing signal skipped: ${err.message}`);
// continue regardless
} Prevention
- Treat typing as best-effort: log and ignore failures.
- Ensure `open <file>` ran before sending presence pings.
- Pass the same file path used for open/await so the session key matches.
When it happens
Trigger: Calling `node scripts/plan-canvas.js typing` with only `--state` and no file; an agent loop that sends typing pings but lost the file reference; typo'ing the subcommand order so a flag lands where the file belongs.
Common situations: Agent orchestrator passes an optional file that was undefined for this turn; user copies the typing example but drops the path; session was never `open`ed so the caller assumes no file needed.
Related errors
- open requires a file path
- await requires a file path
- end requires a file path
- Unknown argument: ${arg}
- Unknown argument: ${arg}
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/9912c83e6ca0736f.
Report an issue: GitHub.