shareAI-lab/learn-claude-code · error · WorkflowInputError
meta.description must be a string
Error message
meta.description must be a string
What it means
After the presence check, validate_meta requires meta['description'] specifically to be a str. Non-string truthy values — a number, list, or dict — pass the earlier truthiness gate but fail here, because the description is surfaced in UIs/logs and compared as text.
Source
Thrown at s16_workflow_runtime/code.py:131
local_lock.release()
with _run_locks_guard:
if not local_lock.locked() and _run_locks.get(run_id) is local_lock:
_run_locks.pop(run_id, None)
# -- Metadata Validation --
def validate_meta(meta):
"""Validate name, description, and optional phases before launch."""
if not isinstance(meta, dict):
raise WorkflowInputError("meta must be an object literal")
if not meta.get("name") or not meta.get("description"):
raise WorkflowInputError("meta requires `name` and `description`")
if not isinstance(meta["name"], str) or not WORKFLOW_NAME_RE.fullmatch(meta["name"]):
raise WorkflowInputError(
"meta.name must be a 1-64 character slug using letters, numbers, '.', '_', or '-'"
)
if not isinstance(meta["description"], str):
raise WorkflowInputError("meta.description must be a string")
if "phases" in meta:
if not isinstance(meta["phases"], list) or not all(
isinstance(phase, str) and phase for phase in meta["phases"]
):
raise WorkflowInputError("meta.phases must be a list of non-empty strings")
return meta
def check_permission(meta, settings=None):
"""Apply the s03 allow/deny gate before launching a workflow."""
settings = settings or {}
if meta["name"] in settings.get("deny", []):
raise WorkflowInputError(f"workflow '{meta['name']}' denied by settings")
return "allow"
# -- Minimal JSON Schema --
class SimpleJsonSchema:View on GitHub (pinned to 985456f4ad)
Solutions
- Quote the description in YAML; ensure the value is a plain string
- Wrap computed descriptions with str(...) at the boundary
- For structured content, serialize to a string (e.g. json.dumps) first
Example fix
# before (YAML) # description: 2024-01-30 <- parsed as a date object # after description: "Nightly ingest run for 2024-01-30"
Defensive patterns
Strategy: type-guard
Validate before calling
def description_is_str(meta: dict) -> bool:
return isinstance(meta.get("description"), str) and bool(meta["description"])
assert description_is_str(meta) Type guard
def meta_description_is_string(meta) -> bool:
return isinstance(meta, dict) and isinstance(meta.get("description"), str) Try / catch
try:
validate_meta(meta)
except WorkflowInputError as exc:
if "description must be a string" in str(exc):
meta = {**meta, "description": str(meta["description"])}
validate_meta(meta)
else:
raise Prevention
- Quote YAML description values
- str() computed descriptions at the boundary
- Beware YAML implicit typing of numbers/booleans/dates
When it happens
Trigger: run(meta={"name": "ingest", "description": 42}) or description set to a list of bullet points ["a", "b"]. YAML configs where an unquoted description parses as a number or boolean (yes/no).
Common situations: YAML implicit typing (description: 2024 becomes an int; description: yes becomes a bool). Programmatically inserting a computed value that happens to be non-text.
Related errors
- meta must be an object literal
- meta.phases must be a list of non-empty strings
- meta requires `name` and `description`
- meta.name must be a 1-64 character slug using letters, numbe
- invalid workflow runId
AI-assisted analysis of shareAI-lab/learn-claude-code@985456f4ad (2026-08-14).
Data as JSON: /api/errors/cf647bb1b63cf1ec.
Report an issue: GitHub.