shareAI-lab/learn-claude-code · error · WorkflowInputError
workflow name must be a string
Error message
workflow name must be a string
What it means
run_workflow is the model-facing adapter: it refuses non-string workflow names with WorkflowInputError('workflow name must be a string') before touching the trusted WORKFLOWS registry. Type-checking happens before the registry lookup, so an int/None/list name never reaches the name-matching code.
Source
Thrown at s16_workflow_runtime/code.py:747
}
def serialize_task(task):
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"]),
}
View on GitHub (pinned to 985456f4ad)
Solutions
- Pass the workflow name as a plain string literal matching a WORKFLOWS key.
- Tighten the tool's input schema (type: string) so the model cannot emit other types.
- Guard in the caller: isinstance(name, str) before invoking.
Example fix
# before await run_workflow(name=workflow_obj) # an object/None # after await run_workflow(name="review")
Defensive patterns
Strategy: type-guard
Validate before calling
if not isinstance(name, str) or not name:
raise TypeError(f"workflow name must be a non-empty string, got {name!r}")
await run_workflow(name, args) Type guard
def is_workflow_name(name) -> bool:
return isinstance(name, str) and bool(WORKFLOW_NAME_RE.match(name)) Try / catch
try:
await run_workflow(name, args)
except WorkflowInputError as e:
if "must be a string" in str(e):
name = str(name) # or reject with a clear message upstream
return await run_workflow(name, args)
raise Prevention
- Declare the tool parameter as type:string in the schema the model sees.
- Keep workflow names as shared string constants in the caller.
- Validate name type and shape (WORKFLOW_NAME_RE) before launching.
When it happens
Trigger: run_workflow(name=None), run_workflow(name=123), or any non-str value arriving from a JSON tool call whose schema failed to enforce the name's type.
Common situations: Tool-call arguments loosely typed (model emitting null for a forgotten field); programmatic callers passing an enum/object; schema drift between client and host.
Related errors
- workflow args must be an object
- args.changes must be a string
- todos must be a list
- todos[{index}] must be an object
- Max retries ({MAX_RETRIES}) exceeded
AI-assisted analysis of shareAI-lab/learn-claude-code@985456f4ad (2026-08-14).
Data as JSON: /api/errors/b3b649b1e086254c.
Report an issue: GitHub.