tinyhumansai/openhuman · warning

invalid approvalMode type (expected required|not_required|nu

Error message

invalid approvalMode type (expected required|not_required|null)

What it means

CardPatch parsing: args["approvalMode"] is present, is not null, and is not a string (todo.rs:263) — e.g. true, 1, an array, or an object. The accepted shapes are exactly the strings "required"/"not_required" or JSON null; anything else fails with this type error before value validation even starts.

Source

Thrown at src/openhuman/agent/tools/todo.rs:263

}

fn patch_from_args(args: &serde_json::Value) -> anyhow::Result<CardPatch> {
    let status: Option<TaskCardStatus> = match args.get("status").and_then(|v| v.as_str()) {
        Some(s) => Some(ops::parse_status(s).map_err(anyhow::Error::msg)?),
        None => None,
    };
    let approval_mode = match args.get("approvalMode") {
        Some(value) if value.is_null() => Some(None),
        Some(value) => match value.as_str() {
            Some("required") => Some(Some(TaskApprovalMode::Required)),
            Some("not_required") => Some(Some(TaskApprovalMode::NotRequired)),
            Some(other) => {
                return Err(anyhow::anyhow!(
                    "invalid approvalMode '{other}' (expected required|not_required|null)"
                ))
            }
            None => {
                return Err(anyhow::anyhow!(
                    "invalid approvalMode type (expected required|not_required|null)"
                ))
            }
        },
        None => None,
    };
    Ok(CardPatch {
        content: None,
        status,
        objective: optional_string(args, "objective"),
        plan: optional_string_array(args, "plan")?,
        assigned_agent: optional_string(args, "assignedAgent"),
        allowed_tools: optional_string_array(args, "allowedTools")?,
        approval_mode,
        acceptance_criteria: optional_string_array(args, "acceptanceCriteria")?,
        evidence: optional_string_array(args, "evidence")?,
        notes: optional_string(args, "notes"),
        blocker: optional_string(args, "blocker"),

View on GitHub (pinned to a221052e0d)

Solutions

  1. Send approvalMode as a string ("required"/"not_required") or null — never a boolean or object
  2. In wrappers, map boolean tri-state (true/false/absent) to the string/null literals explicitly
  3. Omit the field entirely when no override is needed

Example fix

// before
{ "op": "edit", "id": "t1", "approvalMode": true }

// after
{ "op": "edit", "id": "t1", "approvalMode": "required" }
Defensive patterns

Strategy: type-guard

Validate before calling

const a = args as Record<string, unknown>;
if (a?.approvalMode !== undefined && a.approvalMode !== null
    && typeof a.approvalMode !== "string") {
  throw new Error("approvalMode must be a string or null, not " + typeof a.approvalMode);
}

Type guard

function isApprovalModeValue(v: unknown): v is string | null {
  return v === null || typeof v === "string";
}

Try / catch

if e.to_string().contains("invalid approvalMode type") {
    return Ok(ToolResult::error("approvalMode must be the string 'required'/'not_required' or null — booleans/objects are rejected"));
}

Prevention

When it happens

Trigger: Passing a boolean (approvalMode: true), a number, or a nested config object; serializers that map tri-state enums to booleans instead of string|null.

Common situations: Client models with a boolean approval flag; models inventing structured payloads for a scalar field.

Related errors


AI-assisted analysis of tinyhumansai/openhuman@a221052e0d (2026-08-16). Data as JSON: /api/errors/966f1b2053a17aa9. Report an issue: GitHub.