{"record":{"id":"404a318abc5238ee","repo":"Hmbown/CodeWhale","slug":"unknown-control-mode","errorCode":null,"errorMessage":"Unknown control mode","messagePattern":"Unknown control mode","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"crates/tui/plugins/computer-use/src/app-handler.mjs","lineNumber":61,"sourceCode":"  return backends.get(key);\n}\n\nconst sessions = new Map();\nlet controlMode = \"ready\";\nlet controlGeneration = 0;\nlet cleanupPending = false;\n\n/** Human-facing state contains app identity and action names, never task text. */\nexport function controlStatus() {\n  return { mode: controlMode, cleanupPending, sessions: [...sessions.values()]\n    .filter((s) => !s.closed && s.target)\n    .map((s) => ({ target: s.target, mode: s.mode, action: s.action ?? null })) };\n}\n\n// Called only by the launcher's inherited control channel, never an MCP tool.\n// Abort before queuing cleanup so even a held gesture yields to the person.\nexport async function setControlMode(mode) {\n  if (![\"ready\", \"paused\", \"stopped\"].includes(mode)) throw new Error(\"Unknown control mode\");\n  if (mode === \"ready\") {\n    if (cleanupPending) throw new Error(\"Input is still being released; try again in a moment.\");\n    controlMode = mode;\n    return controlStatus();\n  }\n  controlMode = mode;\n  const generation = ++controlGeneration;\n  cleanupPending = true;\n  const results = await Promise.allSettled([...sessions.keys()].map((key) => {\n    const colon = key.indexOf(\":\");\n    return releaseSessionInput(key.slice(colon + 1), key.slice(0, colon), { close: mode === \"stopped\" });\n  }));\n  const failure = results.find((r) => r.status === \"rejected\");\n  // A cleanup failure stays blocked. Resume cannot hide owned input.\n  if (failure) throw failure.reason;\n  if (generation === controlGeneration) cleanupPending = false;\n  return controlStatus();\n}","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/plugins/computer-use/src/app-handler.mjs#L43-L79","documentation":"`setControlMode` in the computer-use app handler only accepts the control modes \"ready\", \"paused\", or \"stopped\". It throws a plain Error(\"Unknown control mode\") for anything else. This function is called only by the launcher's inherited control channel — never as an MCP tool — to pause or resume input injection.","triggerScenarios":"Sending a control-channel message with a mode string other than the three allowed values, e.g. \"pause\" (singular), \"resume\", \"start\", or an empty/garbage token, or a protocol version mismatch where the launcher uses different mode names than the handler expects.","commonSituations":"Hand-rolled launchers or supervision scripts issuing control commands, typos in a mode constant, or a renamed mode after a protocol change with an un-updated sender.","solutions":["Send one of exactly \"ready\", \"paused\", or \"stopped\" on the control channel.","Fix the sender's mode constants to match the handler's accepted set.","Check for protocol drift between the launcher and plugin versions and update both.","Log the received mode string to identify what the sender is actually transmitting."],"exampleFix":"// before\\nsendControl({ mode: \"resume\" });\\n// after\\nsendControl({ mode: \"ready\" });","handlingStrategy":"validation","validationCode":"const MODES = [\"ready\",\"paused\",\"stopped\"];\\nif (!MODES.includes(mode)) throw new Error(`Unknown control mode: ${mode}`);","typeGuard":"const isControlMode = (m) => [\"ready\",\"paused\",\"stopped\"].includes(m);","tryCatchPattern":"try { await setControlMode(mode); } catch (e) { if (e.message === \"Unknown control mode\") { console.error(\"bad control mode from sender:\", mode); } else throw e; }","preventionTips":["Share one modes constant between launcher and handler.","Validate control messages at the channel boundary before dispatch.","Test control-channel senders against all three accepted modes."],"tags":["control-channel","validation","computer-use"],"backgroundTag":"invalid-enum-value","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}