{"record":{"id":"d35ba72c5b1cbd04","repo":"langchain-ai/deepagents","slug":"call-id-and-failed-attempt-must-be-provided-togeth","errorCode":null,"errorMessage":"call_id and failed_attempt must be provided together","messagePattern":"call_id and failed_attempt must be provided together","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"libs/code/deepagents_code/model_retry.py","lineNumber":919,"sourceCode":"        attempt: The 1-indexed retry number about to be attempted.\n        max_retries: The configured maximum retry count.\n        call_id: Opaque ID correlating every attempt of one model call. Omit\n            for producers that predate attempt lifecycle events.\n        failed_attempt: The 0-indexed attempt being superseded. Required to\n            carry `call_id`.\n        output_may_have_started: Whether the superseded attempt may have put\n            message output beyond server control. Conservative by design: the\n            tracker flags before forwarding a chunk.\n\n    Returns:\n        A stream-writer payload consumed by the client renderers.\n\n    Raises:\n        ValueError: If only one of `call_id` and `failed_attempt` is given.\n    \"\"\"\n    if (call_id is None) != (failed_attempt is None):\n        msg = \"call_id and failed_attempt must be provided together\"\n        raise ValueError(msg)\n    event: dict[str, object] = {\n        \"type\": \"model_retry\",\n        \"attempt\": attempt,\n        \"max_retries\": max_retries,\n        \"message\": format_retry_status(attempt, max_retries),\n    }\n    if call_id is not None:\n        event[\"call_id\"] = call_id\n        event[\"failed_attempt\"] = failed_attempt\n        event[\"output_may_have_started\"] = output_may_have_started\n    return event\n\n\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.","sourceCodeStart":901,"sourceCodeEnd":937,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/code/deepagents_code/model_retry.py#L901-L937","documentation":"build_retry_event constructs a model_retry event dict and supports optional retry-correlation fields: call_id and failed_attempt. These two fields are only meaningful as a pair, so providing exactly one raises ValueError('call_id and failed_attempt must be provided together'). This guarantees every retry event either carries the full legacy shape or complete correlation data for downstream matching.","triggerScenarios":"Calling build_retry_event(attempt, max_retries, call_id=\"abc\") without failed_attempt, or failed_attempt=2 without call_id — the XOR check `(call_id is None) != (failed_attempt is None)` fires.","commonSituations":"Refactoring code that started passing call_id but not the new failed_attempt parameter (or vice versa); constructing the event from partially available data when a call hasn't been assigned an ID yet; test fixtures updated incompletely.","solutions":["Pass both call_id and failed_attempt together (or neither) when building the event.","If the call_id is unknown, omit both fields to emit the legacy-shape event instead of a partial one.","Fix call sites/test fixtures to source both values from the same retry attempt record."],"exampleFix":"// before\nbuild_retry_event(attempt=2, max_retries=3, call_id=\"call-1\")  # ValueError\n// after\nbuild_retry_event(attempt=2, max_retries=3, call_id=\"call-1\", failed_attempt=2)","handlingStrategy":"validation","validationCode":"if (call_id is None) != (failed_attempt is None):\n    raise SystemExit(\"Pass call_id and failed_attempt together, or neither\")","typeGuard":null,"tryCatchPattern":"try:\n    event = build_retry_event(attempt, max_retries, call_id=call_id, failed_attempt=failed_attempt)\nexcept ValueError:\n    event = build_retry_event(attempt, max_retries)  # legacy shape","preventionTips":["Type call_id/failed_attempt as a paired tuple or a single optional correlation object in your code.","When updating call sites for new fields, grep all build_retry_event callers and update fixtures together.","Add a unit test asserting partial-correlation inputs are rejected."],"tags":["python","validation","api","correlation"],"backgroundTag":"required-fields-pair","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}