Hmbown/CodeWhale · error · anyhow::Error

--input-json must be a JSON object

Error message

--input-json must be a JSON object

What it means

workflow-tool parses --input-json with serde_json (a parse failure produces its own 'must be a valid Workflow tool input object' context error), then requires the top-level value to be an object. Arrays, strings, numbers, booleans, and null all pass parsing but fail this shape check.

Source

Thrown at crates/tui/src/lib.rs:10616

            exit_workflow_tool_failure();
        }
    }
}

async fn run_workflow_tool_command_inner(
    cli: &Cli,
    args: WorkflowToolArgs,
    plugin_registry: std::sync::Arc<crate::plugins::PluginRegistry>,
) -> Result<()> {
    use crate::tools::spec::ToolSpec;

    if args.approval_source != "explicit-workflow-command" {
        bail!("workflow-tool requires --approval-source explicit-workflow-command");
    }
    let input: serde_json::Value = serde_json::from_str(&args.input_json)
        .context("--input-json must be a valid Workflow tool input object")?;
    if !input.is_object() {
        bail!("--input-json must be a JSON object");
    }
    if !input
        .get("action")
        .and_then(serde_json::Value::as_str)
        .is_some_and(|action| action.eq_ignore_ascii_case("run"))
    {
        bail!("workflow-tool accepts only action=run");
    }

    let workspace = resolve_workspace(cli);
    let mut config = load_config_from_cli(cli)?;
    merge_user_workspace_config(&mut config, cli.config.clone(), &workspace);
    if let Ok(env_url) =
        std::env::var("CODEWHALE_BASE_URL").or_else(|_| std::env::var("DEEPSEEK_BASE_URL"))
    {
        let trimmed = env_url.trim();
        if !trimmed.is_empty() {
            config.base_url = Some(trimmed.to_string());

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. Wrap the payload in an object containing at least {"action":"run", ...}
  2. Pre-validate with `jq type` returning object
  3. Check shell quoting: the JSON must arrive as one argument

Example fix

# before
codewhale workflow-tool --approval-source explicit-workflow-command --input-json '[{"action":"run"}]'

# after
codewhale workflow-tool --approval-source explicit-workflow-command --input-json '{"action":"run","input":{}}'
Defensive patterns

Strategy: validation

Validate before calling

jq -e 'type == "object"' <<<"$INPUT_JSON" >/dev/null || { echo '--input-json must be a JSON object'; exit 1; }

Type guard

const isInputObject = (s) => {
  try { const v = JSON.parse(s); return v !== null && typeof v === 'object' && !Array.isArray(v); }
  catch { return false; }
};

Prevention

When it happens

Trigger: Passing `--input-json '[1,2]'`, `--input-json '"run"'`, or a generator emitting a JSON array of action objects instead of a single object.

Common situations: Hand-built JSON inside shell quotes; a model emitting a batch list of tool calls where one object is expected.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/7198d76cc57f13f4. Report an issue: GitHub.