shareAI-lab/learn-claude-code · error · WorkflowInputError

workflow args must be an object

Error message

workflow args must be an object

What it means

run_workflow requires args to be either None or a JSON-style object; any other type (list, string, number) raises WorkflowInputError('workflow args must be an object'). Individual workflows then validate their own fields (see error 130); this check only enforces the outer shape the runtime and snapshot code depend on (args are stored/read as dicts and compared for resume).

Source

Thrown at s16_workflow_runtime/code.py:751

    return {
        "taskId": task.task_id,
        "taskType": "local_workflow",
        "runId": task.run_id,
        "workflowName": task.meta["name"],
        "status": task.status,
        "usage": dict(task.usage),
        "progress": list(task.progress),
    }


async def run_workflow(name, args=None, resume_from_run_id=None):
    """Model-facing adapter: resolve trusted code from the host registry."""
    if not isinstance(name, str):
        raise WorkflowInputError("workflow name must be a string")
    if name not in WORKFLOWS:
        raise WorkflowInputError(f"unknown workflow '{name}'")
    if args is not None and not isinstance(args, dict):
        raise WorkflowInputError("workflow args must be an object")
    meta, script_fn = WORKFLOWS[name]
    out = await WorkflowTool().call(
        meta,
        script_fn,
        args=args,
        resume_from_run_id=resume_from_run_id,
    )
    return {
        "launched": out["launched"],
        "result": out["result"],
        "task": serialize_task(out["task"]),
    }


WORKFLOW_HANDLERS = {"Workflow": run_workflow}
INHERITS_TOOLS_FROM = "s15"

View on GitHub (pinned to 985456f4ad)

Solutions

  1. Wrap the payload in an object: args={'changes': '...'} instead of a bare list/string.
  2. Pass args=None when there are no arguments (the workflow applies its defaults).
  3. Enforce type:object for args in the tool-call schema the model sees.

Example fix

# before
await run_workflow("review", args=[diff])

# after
await run_workflow("review", args={"changes": diff})
Defensive patterns

Strategy: type-guard

Validate before calling

if args is not None and not isinstance(args, dict):
    raise TypeError("args must be an object or None")
await run_workflow(name, args)

Type guard

def is_valid_args(args) -> bool:
    return args is None or (isinstance(args, dict) and all(isinstance(k, str) for k in args))

Try / catch

try:
    await run_workflow(name, args=args)
except WorkflowInputError as e:
    if "args must be an object" in str(e):
        return await run_workflow(name, args={"value": args})
    raise

Prevention

When it happens

Trigger: run_workflow('review', args=["diff text"]) or args="diff text" — passing a payload whose top level is not a dict.

Common situations: Models emitting a bare string or array for the args parameter; tool schemas not marking args as type:object; callers forwarding an unserialized struct.

Related errors


AI-assisted analysis of shareAI-lab/learn-claude-code@985456f4ad (2026-08-14). Data as JSON: /api/errors/a7d306a47867cd67. Report an issue: GitHub.