zeroclaw-labs/zeroclaw · error
Invalid issue key '{key}'. Expected format: PROJECT-123 (e.g
Error message
Invalid issue key '{key}'. Expected format: PROJECT-123 (e.g. PROJ-42, proj-42) What it means
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.
Source
Thrown at crates/zeroclaw-tools/src/jira_tool.rs:1314
}
}
// ── Input validation ──────────────────────────────────────────────────────────
/// Validates that `issue_key` matches the Jira key format `PROJ-123` or `proj-123`.
/// Prevents path traversal if a crafted key like `../../other` were interpolated
/// directly into the URL.
fn validate_issue_key(key: &str) -> anyhow::Result<()> {
let valid = key.split_once('-').is_some_and(|(project, number)| {
!project.is_empty()
&& project.chars().all(|c| c.is_ascii_alphanumeric())
&& !number.is_empty()
&& number.chars().all(|c| c.is_ascii_digit())
});
if valid {
Ok(())
} else {
anyhow::bail!(
"Invalid issue key '{key}'. Expected format: PROJECT-123 (e.g. PROJ-42, proj-42)"
)
}
}
/// Validates that `key` matches the Jira project key format. Same character
/// class as the project portion of `validate_issue_key` so the two stay in
/// step.
fn validate_project_key(key: &str) -> anyhow::Result<()> {
let valid = !key.is_empty() && key.chars().all(|c| c.is_ascii_alphanumeric());
if valid {
Ok(())
} else {
anyhow::bail!("Invalid project key '{key}'. Expected ASCII alphanumeric, e.g. PROJ")
}
}
// ── Response shaping ──────────────────────────────────────────────────────────View on GitHub (pinned to 88bb9c8533)
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).
Example fix
// before
jira.get_ticket("https://myco.atlassian.net/browse/PROJ-42").await?; // -> error
// after
let key = url.trim().rsplit('/').next().unwrap_or(url.trim());
jira.get_ticket(key).await?; Defensive patterns
Strategy: validation
Validate before calling
// Mirror of the tool's check: 2+ ascii letters, '-', 1+ ascii digits
fn is_valid_issue_key(key: &str) -> bool {
let Some((letters, digits)) = key.split_once('-') else { return false };
letters.len() >= 2
&& letters.chars().all(|c| c.is_ascii_alphabetic())
&& !digits.is_empty()
&& digits.chars().all(|c| c.is_ascii_digit())
}
if !is_valid_issue_key(key.trim()) { anyhow::bail!("bad issue key: {key}"); } Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Invalid project key '{key}'. Expected ASCII alphanumeric, e.
- jira.base_url must not be empty when jira.enabled = true
- jira.api_token must be set (or JIRA_API_TOKEN env var) when
- jira.allowed_actions contains unknown action: '{}'. Valid: g
- approval route '{route}' is not 'channel:recipient' (e.g. 'd
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/81431e15e6c3ab31.
Report an issue: GitHub.