{"record":{"id":"fb514194d59440e7","repo":"zeroclaw-labs/zeroclaw","slug":"jira-api-token-must-be-set-or-jira-api-token-env","errorCode":null,"errorMessage":"jira.api_token must be set (or JIRA_API_TOKEN env var) when jira.enabled = true","messagePattern":"jira\\.api_token must be set \\(or JIRA_API_TOKEN env var\\) when jira\\.enabled = true","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-config/src/schema.rs","lineNumber":22073,"sourceCode":"            if !r.is_empty() && !matches!(r.as_str(), \"us\" | \"eu\" | \"ap\" | \"br\" | \"au\") {\n                anyhow::bail!(\n                    \"tunnel.pinggy.region must be one of: us, eu, ap, br, au (or omitted for auto)\"\n                );\n            }\n        }\n\n        // Jira\n        if self.jira.enabled {\n            if self.jira.base_url.trim().is_empty() {\n                anyhow::bail!(\"jira.base_url must not be empty when jira.enabled = true\");\n            }\n            if self.jira.api_token.trim().is_empty()\n                && std::env::var(\"JIRA_API_TOKEN\")\n                    .unwrap_or_default()\n                    .trim()\n                    .is_empty()\n            {\n                anyhow::bail!(\n                    \"jira.api_token must be set (or JIRA_API_TOKEN env var) when jira.enabled = true\"\n                );\n            }\n            let valid_actions = [\n                \"get_ticket\",\n                \"search_tickets\",\n                \"comment_ticket\",\n                \"list_projects\",\n                \"myself\",\n                \"list_transitions\",\n                \"transition_ticket\",\n                \"create_ticket\",\n            ];\n            for action in &self.jira.allowed_actions {\n                if !valid_actions.contains(&action.as_str()) {\n                    anyhow::bail!(\n                        \"jira.allowed_actions contains unknown action: '{}'. \\\n                         Valid: get_ticket, search_tickets, comment_ticket, list_projects, myself, list_transitions, transition_ticket, create_ticket\",","sourceCodeStart":22055,"sourceCodeEnd":22091,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-config/src/schema.rs#L22055-L22091","documentation":"Thrown by Config::validate when jira.enabled = true and no API token is available from either jira.api_token in config or the JIRA_API_TOKEN environment variable (both checked after trimming). The check is an either/or: config value wins the first branch, the env var is the fallback, and only when both are empty does it bail. This lets deployments keep the secret out of the config file.","triggerScenarios":"Enabling Jira with api_token unset/blank while JIRA_API_TOKEN is also unset or set to empty/whitespace in the process environment; CI or systemd units that strip environment variables; running under a service manager that does not pass user env vars.","commonSituations":"Token configured in the interactive shell but the daemon is started from a different environment (launchd, systemd, Docker); token removed from config for security but env var wiring forgotten; expired/rotated token deleted without replacing either source.","solutions":["Export JIRA_API_TOKEN in the environment of the process that loads the config (systemd Environment=, .env, shell profile)","Or set jira.api_token in config.toml if file-based secrets are acceptable for your setup","Create the token at id.atlassian.com → Security → API token if none exists yet","Verify with `printenv JIRA_API_TOKEN` in the exact launch context of the daemon"],"exampleFix":"# before\n[jira]\nenabled = true\nbase_url = \"https://yourcompany.atlassian.net\"\n# no token anywhere\n\n# after (option A: env var)\n# export JIRA_API_TOKEN=ATATT3fP...\n# after (option B: config)\n[jira]\nenabled = true\nbase_url = \"https://yourcompany.atlassian.net\"\napi_token = \"ATATT3fP...\"","handlingStrategy":"validation","validationCode":"fn jira_token_available(j: &JiraConfig) -> bool {\n    !j.enabled\n        || !j.api_token.trim().is_empty()\n        || !std::env::var(\"JIRA_API_TOKEN\").unwrap_or_default().trim().is_empty()\n}\n// fail fast at startup, not at first Jira call:\nif !jira_token_available(&cfg.jira) {\n    anyhow::bail!(\"JIRA_API_TOKEN missing in this environment\");\n}","typeGuard":null,"tryCatchPattern":"match cfg.validate() {\n    Err(e) if e.to_string().starts_with(\"jira.api_token\") => {\n        eprintln!(\"Provide jira.api_token or export JIRA_API_TOKEN in the service environment\");\n        std::process::exit(78); // EX_CONFIG\n    }\n    other => other?,\n}","preventionTips":["Wire JIRA_API_TOKEN into the unit file/container env at deploy time and assert it in a preflight check","Rotate tokens by updating the env var and restarting, keeping the secret out of config.toml","In CI, fail jobs early if cfg.jira.enabled && env::var(\"JIRA_API_TOKEN\").is_err()"],"tags":["jira","config","validation","credentials","env-var","secrets"],"backgroundTag":"missing-credentials","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}