{"record":{"id":"58d04bf1ba440e2e","repo":"langchain-ai/deepagents","slug":"phase-must-be-one-of-sorted-attempt-phases-go","errorCode":null,"errorMessage":"phase must be one of {sorted(_ATTEMPT_PHASES)}, got {phase!r}","messagePattern":"phase must be one of (.+?), got (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"libs/code/deepagents_code/model_retry.py","lineNumber":950,"sourceCode":"\ndef build_attempt_event(call_id: str, attempt: int, *, phase: str) -> dict[str, object]:\n    \"\"\"Build the custom-stream payload marking one model attempt boundary.\n\n    Args:\n        call_id: Opaque ID shared by every attempt of one model call.\n        attempt: The 0-indexed attempt whose boundary is marked.\n        phase: `\"start\"` before the handler runs, `\"complete\"` after it\n            returns successfully.\n\n    Returns:\n        A stream-writer payload consumed by the client renderers.\n\n    Raises:\n        ValueError: If `phase` is not a known lifecycle phase.\n    \"\"\"\n    if phase not in _ATTEMPT_PHASES:\n        msg = f\"phase must be one of {sorted(_ATTEMPT_PHASES)}, got {phase!r}\"\n        raise ValueError(msg)\n    return {\n        \"type\": \"model_attempt\",\n        \"phase\": phase,\n        \"call_id\": call_id,\n        \"attempt\": attempt,\n    }\n\n\ndef _validated_call_id(value: object) -> str | None:\n    \"\"\"Return `value` as a correlation ID, or `None` when it is untrusted.\"\"\"\n    if (\n        not isinstance(value, str)\n        or not 1 <= len(value) <= _CALL_ID_MAX_LENGTH\n        or any(char not in _CALL_ID_CHARS for char in value)\n    ):\n        return None\n    return value\n","sourceCodeStart":932,"sourceCodeEnd":968,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/code/deepagents_code/model_retry.py#L932-L968","documentation":"build_attempt_event emits a model_attempt lifecycle event whose phase must be one of _ATTEMPT_PHASES = frozenset({\"start\", \"complete\"}) (model_retry.py:133). An unknown phase raises ValueError('phase must be one of [\\'complete\\', \\'start\\'], got {phase!r}'), keeping attempt-event consumers able to rely on a fixed phase vocabulary.","triggerScenarios":"Calling build_attempt_event with phase values like \"begin\", \"finish\", \"error\", \"retry\", or any casing variant (\"Start\"), since membership in the frozenset is exact-match.","commonSituations":"Inventing new lifecycle phases when instrumenting model calls; renaming phases in application code without updating the event builder; passing a human-readable label instead of the canonical phase string.","solutions":["Use exactly \"start\" or \"complete\" for the phase argument.","Normalize labels before calling: map application states to the two supported phases.","If a new phase is genuinely needed, check whether the library version supports it or propose the change upstream — do not pass ad-hoc strings."],"exampleFix":"// before\nbuild_attempt_event(phase=\"begin\", call_id=\"call-1\", attempt=1)  # ValueError\n// after\nbuild_attempt_event(phase=\"start\", call_id=\"call-1\", attempt=1)","handlingStrategy":"type-guard","validationCode":"PHASES = {\"start\", \"complete\"}\nif phase not in PHASES:\n    phase = \"complete\" if phase in {\"finish\", \"end\", \"done\"} else \"start\"","typeGuard":"from typing import Literal, TypeGuard\nPhase = Literal[\"start\", \"complete\"]\ndef is_phase(value: object) -> TypeGuard[Phase]:\n    return value in (\"start\", \"complete\")","tryCatchPattern":"try:\n    event = build_attempt_event(phase=phase, call_id=call_id, attempt=attempt)\nexcept ValueError as exc:\n    logging.warning(\"%s; skipping attempt event\", exc)","preventionTips":["Annotate the phase parameter as Literal['start','complete'] in your wrappers so mypy/pyright reject bad values.","Centralize event building in one helper instead of scattering literal strings.","Map application lifecycle states to the two supported phases at the instrumentation boundary."],"tags":["python","validation","api","enum"],"backgroundTag":"invalid-enum-value","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}