zeroclaw-labs/zeroclaw · error
Jira list_projects failed ({status}): {}
Error message
Jira list_projects failed ({status}): {} What it means
GET {base_url}/rest/api/{2|3}/project returned non-2xx during list_projects; the truncated body is inlined. This is usually pure access failure: 401 wrong email/token pair (Cloud) or wrong PAT (Server/DC), 403 the token user may browse no projects, or 404 from a base_url that is not a Jira site root (edge host, wrong product domain, proxy).
Source
Thrown at crates/zeroclaw-tools/src/jira_tool.rs:424
let req = self
.http
.get(&url)
.timeout(std::time::Duration::from_secs(self.timeout_secs));
let resp = self.authenticated(req).send().await.map_err(|e| {
::zeroclaw_log::record!(
ERROR,
::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Fail)
.with_outcome(::zeroclaw_log::EventOutcome::Failure)
.with_attrs(::serde_json::json!({"error": format!("{}", e)})),
"jira: Jira list_projects request failed"
);
anyhow::Error::msg(format!("Jira list_projects request failed: {e}"))
})?;
let status = resp.status();
if !status.is_success() {
let text = resp.text().await.unwrap_or_default();
anyhow::bail!(
"Jira list_projects failed ({status}): {}",
crate::util_helpers::truncate_with_ellipsis(&text, MAX_ERROR_BODY_CHARS)
);
}
let projects: Vec<Value> = resp.json().await.map_err(|e| {
::zeroclaw_log::record!(
ERROR,
::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Fail)
.with_outcome(::zeroclaw_log::EventOutcome::Failure)
.with_attrs(::serde_json::json!({"error": format!("{}", e)})),
"jira: Failed to parse Jira list_projects response"
);
anyhow::Error::msg(format!("Failed to parse Jira list_projects response: {e}"))
})?;
let keys: Vec<String> = projects
.iter()View on GitHub (pinned to 88bb9c8533)
Solutions
- Call the myself action first: a 401 there means credentials, a 200 means this is a permission or URL problem
- Re-create the API token and update the secret store
- Confirm base_url resolves to the Jira site root and nothing else
- Grant the token user Browse Projects in at least one project
Example fix
// before: secret loaded with a trailing newline -> Jira 401
let token = std::fs::read_to_string("token.txt")?;
// after: trim - whitespace-padded credentials always fail
let token = std::fs::read_to_string("token.txt")?.trim().to_string(); Defensive patterns
Strategy: validation
Validate before calling
// one-time preflight before relying on list_projects
async fn jira_credentials_ok(jira: &JiraTool) -> bool {
jira.execute(serde_json::json!({"action": "myself"}))
.await
.is_ok()
} Type guard
fn is_jira_list_projects_http_failure(err: &anyhow::Error) -> bool {
err.to_string().starts_with("Jira list_projects failed (")
} Try / catch
match jira.execute(list_projects_args).await {
Ok(res) => res,
Err(e) if is_jira_list_projects_http_failure(&e) => {
let msg = e.to_string();
if msg.starts_with("Jira list_projects failed (401") {
halt_and_reauth(&msg) // every other action would 401 too
} else {
return Err(e)
}
}
Err(e) => return Err(e),
} Prevention
- Run a myself preflight at session start and treat 401 as a hard stop for all Jira actions
- Trim secrets at load time
- Store base_url per site in config, not in prompts
- Alert on token age and rotate before expiry
When it happens
Trigger: list_projects with a revoked Atlassian API token; a newly created PAT not yet propagated; a user with no Browse Projects permission anywhere; base_url pointing at a Confluence domain or portal so /rest/api/*/project 404s.
Common situations: Tokens rotated overnight by security policy; site renames invalidating a cached base_url; CI secrets carrying trailing newlines that corrupt Basic auth; Atlassian answering 401 with a 'basic auth with API token' hint when an account password was supplied instead of a token.
Related errors
- Jira get_ticket failed ({status}): {}
- Jira myself failed ({status}): {}
- Jira search_tickets failed ({status}): {}
- Jira comment_ticket failed ({status}): {}
- Jira list_projects users failed ({status}): {}
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/6633eec9dd7a42e1.
Report an issue: GitHub.