can1357/oh-my-pi · error · Error

Unhandled action ${cmd.action}

Error message

Unhandled action ${cmd.action}

What it means

`runAction` switches on `cmd.action` and handles info/logs/stop/kill/restart; the `default` branch throws for any other action value reaching the function. It is an internal exhaustiveness guard: the public `PsAction` type also includes "list", which `runPsCommand` handles before calling `runAction`, so this means an unhandled action leaked through dispatch.

Source

Thrown at packages/coding-agent/src/cli/ps-cli.ts:202

			case "logs":
				await runLogs(cmd, client, name);
				return;
			case "stop":
			case "kill": {
				const timeoutMs = cmd.action === "kill" ? KILL_GRACE_MS : Math.round((cmd.flags.timeout ?? 5) * 1000);
				const result = await client.request({ op: "stop", name, timeoutMs });
				if (result.op !== "stop") throw new Error(`Unexpected broker response ${result.op}`);
				printDaemonResult(cmd, cmd.action === "kill" ? "Killed" : "Stopped", result.daemon);
				return;
			}
			case "restart": {
				const result = await client.request({ op: "restart", name });
				if (result.op !== "restart") throw new Error(`Unexpected broker response ${result.op}`);
				printDaemonResult(cmd, "Restarted", result.daemon);
				return;
			}
			default:
				throw new Error(`Unhandled action ${cmd.action}`);
		}
	} catch (error) {
		console.error(chalk.red(error instanceof Error ? error.message : String(error)));
		process.exitCode = 1;
	}
}

function printDaemonResult(cmd: PsCommandArgs, verb: string, daemon: DaemonSnapshot): void {
	if (cmd.flags.json) console.log(JSON.stringify(daemon, null, 2));
	else console.log(`${verb} ${daemonLabel(daemon)}`);
}

async function runLogs(cmd: PsCommandArgs, client: DaemonBrokerClient, name: string): Promise<void> {
	const lines = Math.max(1, Math.min(1_000, Math.floor(cmd.flags.lines ?? 100)));
	// Follow mode reads the full 1000-line window on every request so overlap
	// trimming sees a stable, sliding tail; the initial print is cut to `lines`.
	const first = await client.request({
		op: "logs",

View on GitHub (pinned to 9690622007)

Solutions

  1. Check the action string you passed — only info/logs/stop/kill/restart are handled by runAction; route `list` through the list path.
  2. If you added a new action, add a corresponding `case` in the switch in `runAction` (ps-cli.ts).
  3. Validate/normalize the action argument at the command-parser boundary before constructing `PsCommandArgs`.

Example fix

// before
switch (cmd.action) {
  case "info": /* ... */
  case "restart": /* ... */
  default:
    throw new Error(`Unhandled action ${cmd.action}`);
}
// after
switch (cmd.action) {
  case "info": /* ... */
  case "restart": /* ... */
  case "pause": {
    const result = await client.request({ op: "pause", name });
    /* ... */
    return;
  }
  default: {
    const exhaustive: never = cmd.action;
    throw new Error(`Unhandled action ${String(exhaustive)}`);
  }
}
Defensive patterns

Strategy: validation

Validate before calling

const ACTIONS = ["info", "logs", "stop", "kill", "restart"] as const;
if (!ACTIONS.includes(cmd.action)) {
  throw new Error(`Action "${cmd.action}" is not valid here; use ${ACTIONS.join("/")}`);
}

Type guard

function isRunnableAction(a: PsAction): a is Exclude<PsAction, "list"> {
  return a !== "list";
}

Try / catch

try {
  await runAction(cmd, name);
} catch (err) {
  if (err instanceof Error && err.message.startsWith("Unhandled action")) {
    console.error(chalk.red(`${cmd.action} is not supported; run \`omp ps --help\``));
    process.exitCode = 1;
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling `runAction` (or `runPsCommand`) with `action` set to "list" or any value outside {info, logs, stop, kill, restart} — e.g. programmatic use of the CLI API, a new action added to `PsAction` without a switch case, or an RPC/plugin invoking the ps command dispatcher directly with an unmapped action.

Common situations: A developer adds a new action to the `PsAction` union and the `PsCommandArgs` parser but forgets to add a `case` in `runAction`; an external caller (script, RPC mode) passes `action: "list"` into `runPsCommand` expecting it to fall through.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/608225877889ab08. Report an issue: GitHub.