{"record":{"id":"0fcf0342d30c9e8e","repo":"shareAI-lab/learn-claude-code","slug":"meta-must-be-an-object-literal","errorCode":null,"errorMessage":"meta must be an object literal","messagePattern":"meta must be an object literal","errorType":"exception","errorClass":"WorkflowInputError","httpStatus":null,"severity":"error","filePath":"s16_workflow_runtime/code.py","lineNumber":123,"sourceCode":"            ) from exc\n        yield\n    finally:\n        if handle is not None:\n            try:\n                fcntl.flock(handle.fileno(), fcntl.LOCK_UN)\n            finally:\n                handle.close()\n        local_lock.release()\n        with _run_locks_guard:\n            if not local_lock.locked() and _run_locks.get(run_id) is local_lock:\n                _run_locks.pop(run_id, None)\n\n\n# -- Metadata Validation --\ndef validate_meta(meta):\n    \"\"\"Validate name, description, and optional phases before launch.\"\"\"\n    if not isinstance(meta, dict):\n        raise WorkflowInputError(\"meta must be an object literal\")\n    if not meta.get(\"name\") or not meta.get(\"description\"):\n        raise WorkflowInputError(\"meta requires `name` and `description`\")\n    if not isinstance(meta[\"name\"], str) or not WORKFLOW_NAME_RE.fullmatch(meta[\"name\"]):\n        raise WorkflowInputError(\n            \"meta.name must be a 1-64 character slug using letters, numbers, '.', '_', or '-'\"\n        )\n    if not isinstance(meta[\"description\"], str):\n        raise WorkflowInputError(\"meta.description must be a string\")\n    if \"phases\" in meta:\n        if not isinstance(meta[\"phases\"], list) or not all(\n            isinstance(phase, str) and phase for phase in meta[\"phases\"]\n        ):\n            raise WorkflowInputError(\"meta.phases must be a list of non-empty strings\")\n    return meta\n\n\ndef check_permission(meta, settings=None):\n    \"\"\"Apply the s03 allow/deny gate before launching a workflow.\"\"\"","sourceCodeStart":105,"sourceCodeEnd":141,"githubUrl":"https://github.com/shareAI-lab/learn-claude-code/blob/985456f4adea6f4df8fbad4112245dbd97444eae/s16_workflow_runtime/code.py#L105-L141","documentation":"validate_meta requires the workflow metadata argument to be a Python dict (object literal) before launch. Anything else — a JSON string, a list, None — raises WorkflowInputError immediately, because every subsequent check (name, description, phases) indexes into it.","triggerScenarios":"Calling run(json.dumps(meta), ...) instead of run(meta, ...). Loading meta from a YAML/JSON file and forgetting json.loads/yaml.safe_load. Passing a dataclass or namedtuple that quacks like meta but is not a dict.","commonSituations":"Config read from disk stays a string. APIs that forward a request body as text. Refactors that introduce a Meta dataclass without converting it at the boundary.","solutions":["Parse before passing: json.loads(meta) / yaml.safe_load(text) and pass the resulting dict","If using a dataclass, convert with dataclasses.asdict() at the call site","Add a boundary check asserting isinstance(meta, dict) right after deserialization"],"exampleFix":"# before\nmeta = Path(\"workflow.json\").read_text()  # str\nrun(meta=meta, ...)\n\n# after\nmeta = json.loads(Path(\"workflow.json\").read_text())\nrun(meta=meta, ...)","handlingStrategy":"type-guard","validationCode":"def is_meta_object(meta) -> bool:\n    return isinstance(meta, dict)\n\nif isinstance(meta, str):\n    meta = json.loads(meta)  # or yaml.safe_load for YAML\nassert is_meta_object(meta)","typeGuard":"def is_workflow_meta(meta) -> bool:\n    \"\"\"Narrow to a dict suitable for validate_meta.\"\"\"\n    return isinstance(meta, dict)","tryCatchPattern":"try:\n    validate_meta(meta)\nexcept WorkflowInputError as exc:\n    if \"object literal\" in str(exc):\n        meta = json.loads(meta) if isinstance(meta, str) else dict(meta)\n        validate_meta(meta)\n    else:\n        raise","preventionTips":["Parse config files at the boundary and pass dicts only","Convert dataclasses with dataclasses.asdict() before run()","Assert isinstance(meta, dict) right after deserialization"],"tags":["workflow","validation","metadata","type-error"],"backgroundTag":null,"analyzedSha":"985456f4adea6f4df8fbad4112245dbd97444eae","analyzedAt":"2026-08-14T22:02:26.028Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}