{"record":{"id":"9a9f8cfead2381c8","repo":"usestrix/strix","slug":"invalid-priority-must-be-one-of-join-valid","errorCode":null,"errorMessage":"Invalid priority. Must be one of: {', '.join(VALID_PRIORITIES)}","messagePattern":"Invalid priority\\. Must be one of: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"warning","filePath":"strix/tools/todo/tools.py","lineNumber":115,"sourceCode":"            tmp_path = Path(tmp.name)\n        tmp_path.replace(path)\n    except Exception:\n        logger.exception(\"todos persist to %s failed\", path)\n\n\ndef _agent_id_from(ctx: RunContextWrapper) -> str:\n    inner = ctx.context if isinstance(ctx.context, dict) else {}\n    return str(inner.get(\"agent_id\") or \"default\")\n\n\ndef _get_agent_todos(agent_id: str) -> dict[str, dict[str, Any]]:\n    return _todos_storage.setdefault(agent_id, {})\n\n\ndef _normalize_priority(priority: str | None, default: str = \"normal\") -> str:\n    candidate = str(priority or default or \"normal\").strip().lower()\n    if candidate not in VALID_PRIORITIES:\n        raise ValueError(f\"Invalid priority. Must be one of: {', '.join(VALID_PRIORITIES)}\")\n    return candidate\n\n\ndef _coerce_priority(priority: str | None, default: str = \"normal\") -> str:\n    try:\n        return _normalize_priority(priority, default)\n    except ValueError:\n        return default\n\n\ndef _sorted_todos(agent_id: str) -> list[dict[str, Any]]:\n    todos_list = [\n        {**todo, \"todo_id\": todo_id} for todo_id, todo in _get_agent_todos(agent_id).items()\n    ]\n    todos_list.sort(key=_todo_sort_key)\n    return todos_list\n\n","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/usestrix/strix/blob/85513391305171ecc6faffe03da4a8bda5e3febb/strix/tools/todo/tools.py#L97-L133","documentation":"The todo tool normalizes priority strings: strip + lower, then membership check against VALID_PRIORITIES = ['low', 'normal', 'high', 'critical'] (strix/tools/todo/tools.py:20). Any other value raises ValueError listing the allowed set. _normalize_priority is the strict path; _coerce_priority wraps it to fall back to the default.","triggerScenarios":"Calling a todo tool function that validates strictly (via _normalize_priority) with priority='urgent', 'P1', 'Normal ' works (case/space tolerant) but 'medium' or 'sev1' fails. Passing None falls back to the default and does not raise.","commonSituations":"LLM agents using their own priority vocabulary ('medium' is the classic collision); mixing todo schemas from other tools (Jira/GitHub labels); upstream enum extended without updating callers.","solutions":["Use one of: low, normal, high, critical (case-insensitive, surrounding whitespace is fine).","Map foreign vocabularies before calling: medium->normal, urgent/critical->critical, low/minor->low.","If you want lenient behavior, route through _coerce_priority so invalid values fall back to the default instead of raising."],"exampleFix":"# before\nupdate_todo(todo_id=\"t1\", priority=\"medium\")   # raises\n\n# after\nupdate_todo(todo_id=\"t1\", priority=\"normal\")   # or \"low\"|\"high\"|\"critical\"","handlingStrategy":"validation","validationCode":"from strix.tools.todo.tools import VALID_PRIORITIES\n\ndef normalize_priority(p: str | None) -> str:\n    p = (p or \"normal\").strip().lower()\n    return p if p in VALID_PRIORITIES else \"normal\"","typeGuard":"from typing import Literal\nPriority = Literal[\"low\", \"normal\", \"high\", \"critical\"]\n\ndef is_priority(v: object) -> bool:\n    return isinstance(v, str) and v.strip().lower() in {\"low\", \"normal\", \"high\", \"critical\"}","tryCatchPattern":"try:\n    add_todo(title=t, priority=p)\nexcept ValueError as exc:\n    if \"Invalid priority\" in str(exc):\n        p = {\"medium\": \"normal\", \"urgent\": \"high\"}.get(p.lower(), \"normal\")\n        add_todo(title=t, priority=p)\n    else:\n        raise","preventionTips":["Map foreign vocabularies (medium->normal) at your boundary before calling todo tools.","Use _coerce_priority when you want lenient defaulting instead of a raise.","Constrain LLM tool args to the four valid values via enum schema."],"tags":["todo","validation","enum","llm-output"],"backgroundTag":null,"analyzedSha":"85513391305171ecc6faffe03da4a8bda5e3febb","analyzedAt":"2026-08-15T05:03:57.275Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}