Troubleshooting¶
Single decision tree for diagnosing a misbehaving jira invocation.
Walk the four checks in order — most failures fall out by step 3.
1. Is the binary what you think it is?¶
Confirms the build SHA and version. If command not found, see
Installation. If a binary is on $PATH but
returns the wrong version, the most common cause is an old install
shadowing a Homebrew or go install update — check which -a jira.
2. Which config and profile are active?¶
data.active_profile names the profile every other command will use.
If it isn't what you expect:
--profile <name>on the failing command overrides everything.JIRA_DEFAULT_PROFILEenvironment variable overrides the file default.default_profilein~/.config/jira-cli/config.tomlis the file default.
See Configuration › Precedence for the full resolution order.
3. Are credentials wired correctly?¶
data.profiles[] lists every configured profile with valid: true|false
and a per-profile error field. Top-level ok: false means at least
one is unhealthy.
Map the per-profile error value to the next step:
credential not found- The keyring (or 1Password) doesn't have an entry for this profile.
Run
jira auth login, or supply the token inline withJIRA_TOKEN_<PROFILE>(the profile name, uppercased). the OS keyring is unavailable(keyring_unavailable)- No Secret Service answered on the session D-Bus — common on WSL and headless Linux. Add one (about a minute on WSL) and keep using the keyring, or switch the profile to the env backend — both paths are in Auth › WSL and headless Linux.
environment variable JIRA_TOKEN_<PROFILE> is not set(env_credential_unset)-
The profile uses the env backend but the variable isn't exported in this shell. Export it, or wrap the invocation in your injector (
op run -- jira ...). The name is derived from the profile —JIRA_TOKEN_DEFAULTfor the default profile — notJIRA_API_TOKEN.WSL gotcha: if your
opis a bridge to the Windowsop.exe(the usual setup for desktop-app auth),op runexecutes its child on Windows, so the variable never reaches your WSLjira— and errors mentioning%PATH%confirm the Windows side handled it. Useexport JIRA_TOKEN_<PROFILE>="$(op read "op://...")"instead; see Authenticate. no Atlassian site exists at <host>(jira_site_not_found)- The profile's
base_urlnames a site that doesn't exist — usually a typo in the site name. (Atlassian's raw 404 body says "Site temporarily unavailable", which reads as an outage; jira detects the tenant-not-found signal and says what's actually wrong.) Fix it withjira config set profiles.<name>.base_url https://<site>.atlassian.net. auth_failed(HTTP 401)- Token is wrong or expired. Rotate it at
id.atlassian.com
and re-run
auth login. The error envelope'shintfield tells you the exact remediation. auth_failed(HTTP 403)- Token is valid but lacks permission for this Jira project. Check the project's permission scheme; the token's user needs Browse Projects + whatever the call requires (Create Issues, Transition Issues, etc.).
server_error/ network timeoutbase_urlmay be wrong, or Jira is down. Re-check the URL withjira config get profiles.<name>.base_urland trycurl -I <base_url>/rest/api/3/myselfwith the token in anAuthorization: Basicheader.
4. Is the local cache the problem?¶
If a --project / --type / --board / --label filter resolves to
an unexpected value (or returns 404 for something that exists in
Jira), the local cache may be stale.
jira cache projects --refresh --output=json
jira cache fields --refresh --output=json
jira cache issuetypes --refresh --output=json
Or nuke and re-prime — any read repopulates what's needed:
See Cache for the full resource list.
Symptom → next step¶
exit 3withcode: validation_failedand afield_errorsmap- Jira rejected one or more fields. The envelope's
errors[0].upstream_field_errorscarries Jira's per-field complaint. Common cases: required field missing under--no-input, customfield value shape wrong (see Custom fields), unknown issue type for the target project. exit 3withcode: arg_value_invalid- The positional argument isn't in the allowed set. The message
lists the valid values. Common cases:
cache clear <unknown>,config theme --name <unknown>. exit 3withcode=issue_type_unknown- The
--typevalue names no issue type on the project's create screen. The valid type names are returned inerrors[0].suggestions; pick one of those. exit 3withscreen schema could not be resolved in strict mode- Strict mode could not fetch the create screen for the payload's
project — usually an unknown project key, or no live connection to
resolve the screen. Check the project with
cache projects. exit 1withauth_failedon a previously-working profile- Token rotated upstream. Re-run
auth login. exit 2withnot_found- Issue / project / board / user doesn't exist for this token. A
403 sometimes surfaces as 404 — check
auth statusto rule out a permission issue first. exit 4withrate_limit- Jira rate-limited the request (HTTP 429), surfaced after auto-retry
was exhausted or skipped. Reads wait and resend within
--max-retry-wait(default30s); mutations and--max-retry-wait=0fail on the first 429. The envelope carrieserrors[0].retry_after_seconds. Raise--max-retry-wait(orJIRA_MAX_RETRY_WAIT), or wait for the window to reset. See Configuration › Rate-limit retry. exit 5withserver_error- Jira's side, or a local IO failure (cache directory not writable,
config file permissions). Check
status.atlassian.com first;
re-run with
--debugif it persists. config initexits withrequired_flag_missing- The command refuses to write unless both
--base-urland--emailare passed; either flag missing is a validation error (exit 3), not a silent overwrite. Re-run with both flags. See Configuration › init.
It looks broken, but it's the contract¶
Behaviours that read like bugs but are deliberate. Check here before filing one.
- Compact output is missing a field I expected.
--output=compactdrops everynull-valued key, recursively, to stay token-lean — so an absent key means the value was null, not that the field doesn't exist. Re-run with--output=jsonfor the full schema, nulls kept. See Output › Modes.- A create succeeded but
.data.keyis empty. - The new key is at
data.issue.key, notdata.key— create wraps the issue object. (A--dry-runreturnsdata.previewinstead, withdry_run: true.) - One bad key failed a multi-key command — did it roll back?
- No. Multi-key commands have no rollback; the good keys were committed. Read
the per-key
data.results[](ok/error) and retry only the failures — a blind retry double-applies the ones that already succeeded. - A search result has no
meta.pagination.total. - Jira's token-paginated
/search/jqlreturns no reliable total, so the CLI omits the field rather than fabricate a0. Paginate onmeta.pagination.isLast/nextCursor(pass the cursor back via--cursor), use--countfor a number, or--allto drain (bounded to 100 pages / 10 000 issues,--unboundedlifts the caps). See Search. --time-spent "1h 30m"fails withinvalid duration.- Durations are space-free:
1h30m,2d4h,45m. Units ared/h/monly, and fractional values (1.5h) are rejected — combine whole units. - A Markdown body lost its @mentions, dates, or panels, with no warning.
- Those ADF constructs have no Markdown spelling, so
--markdown/description_markdowncan't emit them — and--adf-strictcan't flag what never enters the pipeline. Author rich bodies as native ADF via--json-input; keep Markdown for plain prose. See ADF. --dry-runpassed but the real submit failed with a 400 /INVALID_INPUT.- Dry-run validates local shape only; it never contacts Jira. The server applies its own rules on write — required custom fields, its ADF schema, an unknown node that round-tripped fine on read. A clean dry-run means "well-formed", not "Jira will accept it".
--assignee you@example.com --dry-runfails, but works on a real submit.- An email assignee is resolved through a live
/user/search, which dry-run won't call. Pre-resolve toaccountId:<id>for the preview, or drop--dry-runfor the email path. JIRA_PROFILE=…doesn't change which profile runs.- There is no bare
JIRA_PROFILEselector. Pick the profile with--profile <name>,JIRA_DEFAULT_PROFILE, ordefault_profilein the config. (JIRA_PROFILE_<NAME>_*is a different feature — per-profile field overrides.) issue edit KEYexits 3 under an agent or in a pipe.- The bare form opens
$EDITORon the description, which needs a terminal, so a non-TTY or agent context refuses it rather than hang. Pass--summary,--assignee,--markdown, or--json-input. - A destructive command refuses without
--force. --no-inputremoves the confirmation prompt, so--forceis its explicit replacement ondelete/clone/move/ the*-deleteverbs. Multi-key delete needs--forceeven at an interactive terminal. Add--delete-subtasksfor a parent that has subtasks.
Debug invocation¶
When the four checks above don't surface the cause, escalate to a debug capture:
--debug logs the full HTTP roundtrip (request URL, headers, response
status, response body) to stderr. The token is redacted.
meta.upstream_request_id carries Jira's own trace id (the
Atl-Traceid response header) whenever the command reached Jira; quote
it when filing a Jira support ticket. meta.request_id is a locally
generated id for correlating CLI invocations with your own logs — it
has no meaning to Atlassian.
See also¶
- Auth › Troubleshooting access — the error taxonomy from auth.md's perspective.
- Output › Exit codes — the typed-exit-code contract.
- Agents ›
core_contract— the same recovery surface from an agent-runbook angle. - Configuration — env vars and config keys this page references.