{"record":{"id":"9786e44bae73d161","repo":"zeroclaw-labs/zeroclaw","slug":"jira-list-projects-users-failed-status","errorCode":null,"errorMessage":"Jira list_projects users failed ({status}): {}","messagePattern":"Jira list_projects users failed \\((.+?)\\): (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-tools/src/jira_tool.rs","lineNumber":488,"sourceCode":"        })?;\n\n        let users: Vec<Value> = if users_resp.status().is_success() {\n            users_resp.json().await.map_err(|e| {\n                ::zeroclaw_log::record!(\n                    ERROR,\n                    ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Fail)\n                        .with_outcome(::zeroclaw_log::EventOutcome::Failure)\n                        .with_attrs(::serde_json::json!({\"error\": format!(\"{}\", e)})),\n                    \"jira: Failed to parse Jira list_projects users response\"\n                );\n                anyhow::Error::msg(format!(\n                    \"Failed to parse Jira list_projects users response: {e}\"\n                ))\n            })?\n        } else {\n            let status = users_resp.status();\n            let text = users_resp.text().await.unwrap_or_default();\n            anyhow::bail!(\n                \"Jira list_projects users failed ({status}): {}\",\n                crate::util_helpers::truncate_with_ellipsis(&text, MAX_ERROR_BODY_CHARS)\n            );\n        };\n\n        let mut set: tokio::task::JoinSet<(usize, anyhow::Result<Value>)> =\n            tokio::task::JoinSet::new();\n        let mut statuses_results = vec![json!([]); keys.len()];\n\n        for (i, key) in keys.iter().enumerate() {\n            if set.len() >= STATUS_CONCURRENCY {\n                let Some(Ok((idx, result))) = set.join_next().await else {\n                    continue;\n                };\n                statuses_results[idx] = result.map_err(|e| {\n                    ::zeroclaw_log::record!(\n                        ERROR,\n                        ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Fail)","sourceCodeStart":470,"sourceCodeEnd":506,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-tools/src/jira_tool.rs#L470-L506","documentation":"list_projects enriches each project with assignable users; when that secondary per-project users request answers non-2xx (the else branch taken after the earlier response could not be reused), this error fires with status and truncated body. Typically 403: the token user lacks Browse Users or project-role visibility, or the deployment restricts user-picking endpoints (common on Jira Cloud after the user-API tightening); less often a plain 401.","triggerScenarios":"list_projects where the main project list succeeds but the follow-up per-project users fetch is denied - a bot without Browse Users rights, a Cloud site restricting user endpoints for API-token auth, or a proxy stripping the Authorization header from just that path.","commonSituations":"Least-privilege bot accounts; Jira Cloud's GDPR-era user API restrictions returning 403 for Basic-auth tokens; Server/DC PATs without elevated rights; partial outages of the Jira user service.","solutions":["Check the status: 403 -> raise the bot's permission (Browse Users / site access) or accept that user enrichment cannot run","If on Cloud and the body mentions deprecated or restricted user APIs, upgrade zeroclaw-tools for the current endpoint","Reproduce outside the agent: curl -u email:token \"$BASE/rest/api/3/users/search\" (or the assignable-users endpoint for one project)","If user data is not needed, tolerate the failure and report the project list without enrichment once permissions cannot be changed"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"fn is_jira_users_http_failure(err: &anyhow::Error) -> bool {\n    err.to_string()\n        .starts_with(\"Jira list_projects users failed (\")\n}","tryCatchPattern":"match jira.execute(list_projects_args).await {\n    Ok(res) => res,\n    Err(e) if is_jira_users_http_failure(&e) => {\n        // the project list itself succeeded server-side; only the\n        // per-project users fetch was denied (usually 403).\n        // Retry with an elevated token or report the permission gap.\n        report_permission_gap(&e)\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Grant the bot Browse Users or project-role membership up front","Audit which Jira user endpoints the deployment allows for token auth","Treat user-enrichment failures as a permission gap, not a data problem","Reproduce with curl before changing permissions"],"tags":["rust","zeroclaw","jira","users","permissions","http-status"],"backgroundTag":"jira-rest-api-error","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}