{"record":{"id":"819dee74b0b2ddde","repo":"affaan-m/ECC","slug":"typing-failed-http-res-statuscode","errorCode":null,"errorMessage":"typing failed (HTTP ${res.statusCode})","messagePattern":"typing failed \\(HTTP (.+?)\\)","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/plan-canvas.js","lineNumber":307,"sourceCode":"      : 'Address the feedback, then run `ecc-plan-canvas await <file> --reply \"<what you changed>\"` to answer in the canvas and keep listening.';\n  } else if (result.status === 'ended') {\n    result.next_step =\n      result.endedBy === 'user'\n        ? 'The user ended this review. Stop polling and deliver any remaining updates in chat; do not reopen uninvited.'\n        : 'Session ended. Stop polling.';\n  }\n  return result;\n}\n\n// Show the human an activity indicator in the canvas chat. Cheap and\n// fire-and-forget: a failed signal must never derail the actual work.\nasync function cmdTyping(file, args, { port }) {\n  if (!file) throw new Error('typing requires a file path');\n  const state = valueAfter(args, '--state') || 'typing';\n  if (!(await healthCheck(port))) return { status: 'no-server' };\n  const key = sessionKeyFor(canonicalizeArtifactPath(file));\n  const res = await request(port, 'POST', `/api/session/${key}/typing`, { state });\n  if (res.statusCode !== 200) throw new Error(res.body.error || `typing failed (HTTP ${res.statusCode})`);\n  return { status: 'ok', state, presence: res.body.presence };\n}\n\n// Report feedback the human sent that no agent has picked up yet. Reads state\n// directly so it answers even when the server has idled out.\nfunction cmdPending({ stateDir }) {\n  const store = createSessionStore({ stateDir });\n  const waiting = store\n    .list()\n    .filter(session => session.status !== 'ended' && session.pending > 0)\n    .map(session => ({ file: session.file, pending: session.pending, updatedAt: session.updatedAt }));\n  return {\n    status: waiting.length ? 'pending' : 'clear',\n    sessions: waiting,\n    next_step: waiting.length\n      ? 'Run `ecc-plan-canvas await <file>` for each file above to receive the messages.'\n      : 'No canvas feedback is waiting.'\n  };","sourceCodeStart":289,"sourceCodeEnd":325,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/plan-canvas.js#L289-L325","documentation":"cmdTyping POSTs the presence state to /api/session/<key>/typing and expects HTTP 200. On any other status it throws 'typing failed (HTTP <status>)', unless the response body carried an explicit error message, which is preferred. Because the body fallback exists, a bare status message usually means the server returned an unexpected body shape or an empty error.","triggerScenarios":"Posting a typing signal when the server rejects the request: 404 because the session key no longer exists (server restarted or session ended via /api/end), 400 for an unsupported --state value, 500 on a server-side state write failure.","commonSituations":"The canvas server restarted (idle timeout) and wiped sessions while an agent keeps signaling typing; a typo'd --state like 'writting' rejected with 400; two ECC versions disagreeing on the /typing route so the old client hits a moved endpoint (404/405).","solutions":["Check the returned status: 404 means the session is gone — rerun `ecc-plan-canvas open <file>` to re-register, then resume typing signals.","Verify the --state value is one the server accepts (e.g. typing/thinking/idle); fix typos.","Confirm the CLI and server come from the same ECC version (`ecc-plan-canvas stop` then reopen) so the route matches.","Wrap the typing call defensively in automation — per design a failed typing signal must never derail the actual work, so catch and log rather than abort."],"exampleFix":"// before (aborts the pipeline)\nawait cmdTyping(file, args, ctx);\n\n// after (typing is best-effort)\ntry {\n  await cmdTyping(file, args, ctx);\n} catch (err) {\n  console.warn(`typing signal skipped: ${err.message}`);\n}","handlingStrategy":"try-catch","validationCode":"const VALID_STATES = new Set(['typing', 'thinking', 'idle']);\nif (!VALID_STATES.has(state)) throw new Error(`unsupported typing state: ${state}`);\nif (!(await healthCheck(port))) return; // nothing to signal","typeGuard":null,"tryCatchPattern":"try {\n  await cmdTyping(file, args, ctx);\n} catch (err) {\n  console.warn(`typing signal skipped: ${err.message}`); // 404 => session gone; reopen if needed\n}","preventionTips":["Wrap typing calls in try/catch — by design they must never derail real work.","On 404, reopen the session rather than retrying the same dead key.","Keep CLI and server on the same ECC version so the /typing route matches.","Health-check the server before emitting presence signals."],"tags":["http","cli","plan-canvas","presence"],"backgroundTag":"http-error-response","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}