zeroclaw-labs/zeroclaw · error
Invalid project key '{key}'. Expected ASCII alphanumeric, e.
Error message
Invalid project key '{key}'. Expected ASCII alphanumeric, e.g. PROJ What it means
Local format validation of a project key used by create_ticket: the key must be non-empty and every character ASCII alphanumeric. Notably it rejects '-' and other punctuation, so passing a full issue key ("PROJ-42") here fails. It runs before the summary/issue_type checks and before any network call.
Source
Thrown at crates/zeroclaw-tools/src/jira_tool.rs:1328
});
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 ──────────────────────────────────────────────────────────
/// Safely extracts the first 10 characters (date prefix) from a string.
/// Returns the full string if it is shorter than 10 characters instead of
/// panicking on out-of-bounds slice indexing.
fn date_prefix(s: &str) -> &str {
s.get(..10).unwrap_or(s)
}
fn shape_basic(raw: &Value) -> Value {
let f = &raw["fields"];
let rf = &raw["renderedFields"];
// Build a lookup map from comment ID → rendered body for O(1) access
// instead of scanning the rendered array for each comment (O(n²)).View on GitHub (pinned to 88bb9c8533)
Solutions
- Pass only the project key, e.g. "PROJ", not an issue key.
- Make the project key a required, trimmed configuration value and fail fast at startup if it is blank.
- Validate the format in your own layer before calling create_ticket (see below).
Example fix
// before
jira.create_ticket("PROJ-42", "Bug", "Crash on save", None, None, None, None).await?; // -> error: issue key passed as project
// after
jira.create_ticket("PROJ", "Bug", "Crash on save", None, None, None, None).await?; Defensive patterns
Strategy: validation
Validate before calling
fn is_valid_project_key(key: &str) -> bool {
!key.is_empty() && key.chars().all(|c| c.is_ascii_alphanumeric())
}
if !is_valid_project_key(project.trim()) { anyhow::bail!("bad project key"); } Prevention
- Fail fast at startup if the configured default project key is blank.
- Strip anything after '-' before passing (guards against issue/project key confusion).
- Keep project keys in typed config, not free-form user input.
When it happens
Trigger: Calling create_ticket with an issue key instead of a project key ("PROJ-42"); an empty project string from a missing config value; project keys with punctuation that some legacy Jira instances allow; whitespace in the key from untrimmed config.
Common situations: Config files storing the default project as blank; agents conflating project key and issue key; migrating from instances whose project keys contain characters Jira no longer permits.
Related errors
- Invalid issue key '{key}'. Expected format: PROJECT-123 (e.g
- 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/64ebf84644d7529a.
Report an issue: GitHub.