{"record":{"id":"c2884ca31a24639f","repo":"google-gemini/gemini-cli","slug":"invalid-or-missing-issue-id-format-issue-id","errorCode":null,"errorMessage":"Invalid or missing 'issue_id' format: {issue_id}","messagePattern":"Invalid or missing 'issue_id' format: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"tools/caretaker-agent/cloudrun/triage-worker/utils/validator.py","lineNumber":82,"sourceCode":"\n    if metadata.get(\"quality\") == \"OK\":\n        effort = metadata.get(\"effort_estimate\")\n        if effort not in [\"SMALL\", \"MEDIUM\", \"LARGE\"]:\n            raise ValueError(\n                f\"Invalid or missing 'effort_estimate': {effort}\"\n            )\n\n        spec = data.get(\"workable_spec\")\n        if not isinstance(spec, dict):\n            raise ValueError(\"Missing 'workable_spec'\")\n        \n        issue_id = spec.get(\"issue_id\")\n        pattern = r\"^[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+#[0-9]+$\"\n        valid_id = isinstance(issue_id, str) and bool(\n            re.match(pattern, issue_id)\n        )\n        if not valid_id:\n            raise ValueError(\n                f\"Invalid or missing 'issue_id' format: {issue_id}\"\n            )\n\n        _assert_section_schema(spec, \"summary\", {\n            \"problem\": str,\n            \"root_cause\": str,\n            \"context\": str,\n        })\n        _assert_section_schema(spec, \"implementation_plan\", {\n            \"files_to_modify\": [str],\n            \"steps\": [str],\n        })\n        _assert_section_schema(spec, \"testing_strategy\", {\n            \"test_file\": str,\n            \"expected_behavior\": str,\n            \"verification_steps\": [str],\n            \"framework\": str,\n        })","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/google-gemini/gemini-cli/blob/5024443c7217464a66e98f80d73172a26440bd8f/tools/caretaker-agent/cloudrun/triage-worker/utils/validator.py#L64-L100","documentation":"This ValueError is thrown by validate_triage_result() when the LLM triage output declares quality='OK' but the workable_spec.issue_id field does not match the required 'owner/repo#number' regex pattern (^[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+#[0-9]+$). The validator runs after json.loads on the triage result to enforce structural correctness of the workable spec before it is persisted or judged. It is a schema-integrity guard, not an I/O failure.","triggerScenarios":"Called inside validate_triage_result(data) when data['triage_metadata']['quality'] == 'OK'. The spec = data.get('workable_spec') is a dict but spec.get('issue_id') is either None, a non-string type, or a string that omits the '#', the '/', or uses disallowed characters (e.g. spaces, 'owner/repo', '12345', 'owner repo#5', 'owner/repo#abc').","commonSituations":"The triage LLM hallucinates a numeric-only or URL-style issue_id instead of the slug format. A prompt or model regression causes the agent to emit the issue_id under a different key (e.g. 'issueId'). The spec was hand-crafted or generated by generate_golden_spec and the issue_id field was left out or malformed during JSON synthesis.","solutions":["Inspect the full workable_spec dict in the triage output and confirm issue_id is present as a string in 'owner/repo#NNN' form (e.g. 'facebook/react#28052').","If the LLM is producing a malformed id, update the triage system prompt / instructions to enforce the exact issue_id format with examples, then re-run the triage.","If you are constructing the spec programmatically (e.g. in generate_golden_spec), build issue_id with f\"{owner}/{repo}#{issue_number}\" before validation.","Add a unit test that feeds a quality='OK' payload through validate_triage_result to catch regressions in the issue_id format."],"exampleFix":"// before\nworkable_spec = {\"issue_id\": \"28052\", ...}\n// after\nworkable_spec = {\"issue_id\": f\"{owner}/{repo}#{issue_number}\", ...}","handlingStrategy":"validation","validationCode":"import re\n\ndef is_valid_issue_id(owner: str, repo: str, issue_number: int) -> bool:\n    candidate = f\"{owner}/{repo}#{issue_number}\"\n    return bool(re.match(r\"^[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+#[0-9]+$\", candidate))\n\n# Before calling validate_triage_result, build and check:\n# spec['issue_id'] = f\"{owner}/{repo}#{issue_number}\"","typeGuard":"from typing import Any\n\ndef has_valid_issue_id(spec: Any) -> bool:\n    if not isinstance(spec, dict):\n        return False\n    issue_id = spec.get('issue_id')\n    if not isinstance(issue_id, str):\n        return False\n    import re\n    return bool(re.match(r\"^[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+#[0-9]+$\", issue_id))","tryCatchPattern":"try:\n    validate_triage_result(data)\nexcept ValueError as e:\n    if 'issue_id' in str(e):\n        data.setdefault('workable_spec', {})['issue_id'] = f\"{owner}/{repo}#{issue_number}\"\n        validate_triage_result(data)\n    else:\n        raise","preventionTips":["Always construct issue_id with f\"{owner}/{repo}#{issue_number}\" rather than relying on the LLM to format it.","Add a pytest case asserting validate_triage_result accepts a well-formed OK payload and rejects malformed issue_ids.","Log the workable_spec dict before validation during eval runs to catch format drift early."],"tags":["validation","triage-worker","workable-spec","schema","python"],"backgroundTag":null,"analyzedSha":"5024443c7217464a66e98f80d73172a26440bd8f","analyzedAt":"2026-08-12T06:01:53.711Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}