{"record":{"id":"81431e15e6c3ab31","repo":"zeroclaw-labs/zeroclaw","slug":"invalid-issue-key-key-expected-format-projec","errorCode":null,"errorMessage":"Invalid issue key '{key}'. Expected format: PROJECT-123 (e.g. PROJ-42, proj-42)","messagePattern":"Invalid issue key '(.+?)'\\. Expected format: PROJECT-123 \\(e\\.g\\. PROJ-42, proj-42\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-tools/src/jira_tool.rs","lineNumber":1314,"sourceCode":"    }\n}\n\n// ── Input validation ──────────────────────────────────────────────────────────\n\n/// Validates that `issue_key` matches the Jira key format `PROJ-123` or `proj-123`.\n/// Prevents path traversal if a crafted key like `../../other` were interpolated\n/// directly into the URL.\nfn validate_issue_key(key: &str) -> anyhow::Result<()> {\n    let valid = key.split_once('-').is_some_and(|(project, number)| {\n        !project.is_empty()\n            && project.chars().all(|c| c.is_ascii_alphanumeric())\n            && !number.is_empty()\n            && number.chars().all(|c| c.is_ascii_digit())\n    });\n    if valid {\n        Ok(())\n    } else {\n        anyhow::bail!(\n            \"Invalid issue key '{key}'. Expected format: PROJECT-123 (e.g. PROJ-42, proj-42)\"\n        )\n    }\n}\n\n/// Validates that `key` matches the Jira project key format. Same character\n/// class as the project portion of `validate_issue_key` so the two stay in\n/// step.\nfn validate_project_key(key: &str) -> anyhow::Result<()> {\n    let valid = !key.is_empty() && key.chars().all(|c| c.is_ascii_alphanumeric());\n    if valid {\n        Ok(())\n    } else {\n        anyhow::bail!(\"Invalid project key '{key}'. Expected ASCII alphanumeric, e.g. PROJ\")\n    }\n}\n\n// ── Response shaping ──────────────────────────────────────────────────────────","sourceCodeStart":1296,"sourceCodeEnd":1332,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-tools/src/jira_tool.rs#L1296-L1332","documentation":"Local format validation of an issue key: it must be LETTERS-DIGITS where the letters part is 2+ ASCII alphabetic characters (either case) and the number part is one or more ASCII digits with no leading restrictions beyond being non-empty. Used by get_ticket, comment_ticket, fetch_transitions, transition_ticket, and create_ticket (for parent_key). It fails before any network call, catching malformed keys like 'PROJ', '-42', 'PROJ-12a', or embedded whitespace.","triggerScenarios":"Passing a bare project key (\"PROJ\") instead of an issue key; passing a URL (\"https://x/browse/PROJ-42\"); keys with non-ASCII or punctuation; passing an issue id number (\"12345\") instead of the key; whitespace from untrimmed user input.","commonSituations":"Users pasting full Jira URLs into a CLI/agent; confusion between numeric issue id and issue key; copy-paste artifacts (trailing spaces, unicode dashes) from docs or chat messages; building keys by concatenation where the number came back empty.","solutions":["Supply the key in PROJECT-123 form, e.g. PROJ-42 or proj-42 (matching is case-insensitive per the message).","If users paste URLs, extract the trailing /browse/PROJ-42 segment before calling the tool.","Trim input and re-check the shape in your own layer (see validation code below)."],"exampleFix":"// before\njira.get_ticket(\"https://myco.atlassian.net/browse/PROJ-42\").await?; // -> error\n\n// after\nlet key = url.trim().rsplit('/').next().unwrap_or(url.trim());\njira.get_ticket(key).await?;","handlingStrategy":"validation","validationCode":"// Mirror of the tool's check: 2+ ascii letters, '-', 1+ ascii digits\nfn is_valid_issue_key(key: &str) -> bool {\n    let Some((letters, digits)) = key.split_once('-') else { return false };\n    letters.len() >= 2\n        && letters.chars().all(|c| c.is_ascii_alphabetic())\n        && !digits.is_empty()\n        && digits.chars().all(|c| c.is_ascii_digit())\n}\nif !is_valid_issue_key(key.trim()) { anyhow::bail!(\"bad issue key: {key}\"); }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Extract keys from pasted URLs before use (take the segment after /browse/).","Trim all user-supplied keys at ingest.","Remember numeric issue ids are NOT keys — resolve id->key via Jira search if needed."],"tags":["jira","validation","issue-key","format"],"backgroundTag":"invalid-identifier-format","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}