shareAI-lab/learn-claude-code · error · WorkflowInputError
workflow '{meta['name']}' denied by settings
Error message
workflow '{meta['name']}' denied by settings What it means
check_permission applies the s03 allow/deny gate before launch: if meta['name'] appears in settings['deny'], the workflow is refused with WorkflowInputError naming the denied workflow. This is a policy enforcement error, not a data-format one — the meta is valid but the operator has banned this workflow by name.
Source
Thrown at s16_workflow_runtime/code.py:144
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:
"""Tiny validator backing agent({schema}):
object/array/string/boolean/number + required keys."""
def __init__(self, schema):
self.schema = schema
def validate(self, value, schema=None):
schema = self.schema if schema is None else schema
if "enum" in schema and value not in schema["enum"]:
return False, f"expected one of {schema['enum']}"
t = schema.get("type")
if t == "object":
if not isinstance(value, dict):View on GitHub (pinned to 985456f4ad)
Solutions
- If the workflow should run, remove or correct its name in the settings deny list
- If denial is intended, stop the invoking scheduler/job as well
- Pre-check before launch: if meta['name'] in settings.get('deny', []), skip gracefully instead of letting the exception propagate
Example fix
# before
settings = {"deny": ["ingest"]}
run(workflow, meta=meta, settings=settings) # raises if name == 'ingest'
# after
if meta["name"] not in settings.get("deny", []):
run(workflow, meta=meta, settings=settings) Defensive patterns
Strategy: validation
Validate before calling
def workflow_is_allowed(meta: dict, settings: dict) -> bool:
return meta.get("name") not in (settings or {}).get("deny", [])
assert workflow_is_allowed(meta, settings), f"{meta['name']!r} is denied by settings" Type guard
def is_not_denied(meta: dict, settings: dict | None) -> bool:
return meta.get("name") not in (settings or {}).get("deny", []) Try / catch
try:
check_permission(meta, settings)
except WorkflowInputError as exc:
if "denied by settings" in str(exc):
# intentional policy: skip gracefully instead of crashing the scheduler
log.info("skipping denied workflow %s", meta["name"])
return
raise Prevention
- Pre-check names against the deny list before launching
- Keep deny lists per environment and review them during promotion
- When disabling a workflow, also disable its scheduler entry
When it happens
Trigger: settings = {"deny": ["ingest"]} and run(meta={"name": "ingest", ...}). Deny lists copied from another environment where the same name means a different workflow. Names added to deny for incident response while scheduled jobs keep firing.
Common situations: Operators disabling a misbehaving workflow via settings, then a cron/scheduler still attempting it. Config promotion carrying a production deny list into staging where the name collides with a legitimate workflow.
Related errors
- Memory directory escapes the workspace
- Task store escapes the workspace
- expected a JSON list
- MCP names cannot normalize to an empty string
- could not allocate a unique workflow runId
AI-assisted analysis of shareAI-lab/learn-claude-code@985456f4ad (2026-08-14).
Data as JSON: /api/errors/db74c271b7fc4d88.
Report an issue: GitHub.