Error Codes
Every failure carries a numeric code in the --json error payload
({"code": 2002, …}). The process exit status is normally 1 (Ctrl+C at a
prompt uses 130); set BB_DETAILED_EXIT_CODES=1 for a coarse status per
failure class (see Exit codes). Branch on code
for anything finer. Ctrl-F the number below.
Error code ranges
Section titled “Error code ranges”| Range | Category | Description |
|---|---|---|
| 1xxx | Authentication | Login, credentials, and token issues |
| 2xxx | API | Bitbucket API request failures |
| 3xxx | Git | Local git operations |
| 4xxx | Configuration | Config file read/write issues |
| 5xxx | Validation | Invalid input or missing required fields |
| 6xxx | Context | Repository/workspace detection issues |
| 7xxx | Network | Transport/network failures before API response |
| 8xxx | Output formatting | --json fields and --jq evaluation issues |
| 9xxx | Shell completion / Unknown | Completion install/uninstall failures and uncategorized errors |
| 10xxx | CI outcome | A watched pipeline or pull request check did not pass |
Authentication errors (1xxx)
Section titled “Authentication errors (1xxx)”1001 - AUTH_REQUIRED
Section titled “1001 - AUTH_REQUIRED”Message: Authentication required
Cause: You haven’t logged in yet, or your credentials have been cleared.
bb auth login also returns it outside an interactive terminal when no API
token is given, because browser login needs a person to finish it.
Solution:
bb auth login# Scripts, CI and agents:1002 - AUTH_INVALID
Section titled “1002 - AUTH_INVALID”Message: Invalid credentials
Cause: Your credentials were rejected by Bitbucket at request time. This is the code emitted for any 401 response that was not recovered by an OAuth refresh; e.g. a wrong API token, a revoked password, or basic-auth requests with bad credentials.
Solution:
- Verify your Atlassian account email for API-token login
- Generate a new API token at Bitbucket API Tokens
- Re-authenticate:
bb auth logoutbb auth loginThe CLI prints this next step alongside the error:
Your Bitbucket credentials were rejected. Run
bb auth loginto re-authenticate.
1003 - AUTH_EXPIRED
Section titled “1003 - AUTH_EXPIRED”Message: one of:
OAuth token expired. Run 'bb auth login' to re-authenticate.Failed to refresh OAuth token. Run 'bb auth login' to re-authenticate., followed by Bitbucket’s reason when it gives one
Cause: Specifically: an OAuth access token expired and Bitbucket rejected the refresh (refresh token revoked or expired). The CLI refreshes before a request whose token has expired or is about to, and again after a 401; a rejected refresh at either point reports this code. For non-OAuth flows, a stale token surfaces as AUTH_INVALID (1002) instead.
Solution:
- Re-run
bb auth loginto perform a fresh OAuth flow - If that also fails, create a new API token in Bitbucket settings and switch auth methods
API errors (2xxx)
Section titled “API errors (2xxx)”2001 - API_REQUEST_FAILED
Section titled “2001 - API_REQUEST_FAILED”Message: API request failed
Cause: Bitbucket answered with an unexpected HTTP status below 500 that isn’t 401/403/404/429; typically 400 (malformed request body) or 409 (conflict, e.g. merging a pull request that is already merged). The server did respond, so this is not a connectivity problem.
Solution: Read message and response in the JSON error payload; they
carry Bitbucket’s own explanation. When Bitbucket returns a bare plain-text body
(e.g. Bad Request from the request parser before the endpoint runs), the body
text becomes message instead of axios’s generic “Request failed with status
code 400”.
bb pr merge 42 --json 2> err.jsonjq '.statusCode, .message, .response' err.jsonbb api goes further: its --json error object also includes headers and the
transport’s statusText, and bb api -i prints the status line and headers to
stderr on failure. See API Command.
Connection failures are 7001; server faults are 2005.
2002 - API_NOT_FOUND
Section titled “2002 - API_NOT_FOUND”Message: Resource not found
Cause: The requested repository, PR, or resource doesn’t exist.
Solution:
- Check spelling of workspace and repository names
- Verify the resource exists in Bitbucket
- Ensure you have access to the repository
Where the message doesn’t already name the missing resource, the CLI appends:
Verify the id or slug you passed, and that –workspace/–repo point at the right repository your token can see.
The hint is omitted when the message is already specific (for example
Pull request 999 not found in acme/demo.) and for bb api, where you supplied
the URL yourself.
2003 - API_FORBIDDEN
Section titled “2003 - API_FORBIDDEN”Message: Access denied
Cause: Bitbucket rejected the operation. Missing scopes, account permissions, or repository restrictions can cause a 403.
Solution:
- Check account permissions and repository restrictions.
- For API tokens, check the command scopes and create a new token if needed. Existing API-token scopes cannot be changed.
- For OAuth, check the consumer’s permissions and sign in again.
The CLI prints this next step alongside the error:
Your token may be missing a required scope, or your account may lack permission. For API tokens, create a token with the required scopes. For OAuth, check consumer permissions, then run
bb auth login.Docs: https://bitbucket-cli.paulvanderlei.com/reference/token-scopes/
2004 - API_RATE_LIMITED
Section titled “2004 - API_RATE_LIMITED”Message: Rate limit exceeded
Cause: Bitbucket returned 429 and the CLI’s three automatic retries; which
honour the Retry-After header; were all exhausted.
Solution: Reduce request volume. Prefer --limit over --all, and batch
with bb api --paginate instead of looping single calls:
bb pr list --limit 25 --jsonbb api /repositories/myworkspace/myrepo/pullrequests --paginate --json2005 - API_SERVER_ERROR
Section titled “2005 - API_SERVER_ERROR”Message: Bitbucket server error
Cause: Bitbucket’s servers are experiencing issues.
Solution:
- Check status.bitbucket.org
- Retry after a few minutes
Git errors (3xxx)
Section titled “Git errors (3xxx)”3001 - GIT_NOT_REPOSITORY
Section titled “3001 - GIT_NOT_REPOSITORY”Reserved. No code path currently emits 3001; running outside a git
repository surfaces as 6001 CONTEXT_REPO_NOT_FOUND.
Don’t branch on 3001 in scripts.
3002 - GIT_COMMAND_FAILED
Section titled “3002 - GIT_COMMAND_FAILED”Message: Git command failed
Cause: A git operation (clone, fetch, checkout) failed.
Solution:
- Ensure git is installed and in your PATH
- Check git error message for details
- Verify you have proper SSH keys or credentials configured
3003 - GIT_REMOTE_NOT_FOUND
Section titled “3003 - GIT_REMOTE_NOT_FOUND”Message: No Bitbucket remote found
Cause: The repository has no remote pointing to Bitbucket.
Solution:
- Add a Bitbucket remote:
- Or use explicit flags:
-w <workspace> -r <repo>
Config errors (4xxx)
Section titled “Config errors (4xxx)”4001 - CONFIG_READ_FAILED
Section titled “4001 - CONFIG_READ_FAILED”Message: Cannot read config file
Cause: The configuration file is corrupted or unreadable, or the config file or directory is readable by other users. The insecure-permissions case says so and names the fix:
Config directory has insecure permissions (755); expected 700. Run: chmod 700 /Users/you/.config/bbSolution:
- Check file permissions (run the
chmodfrom the message for the insecure-permissions case) - If corrupted, delete and recreate:
# macOS/Linuxrm ~/.config/bb/config.jsonbb auth login
# Windowsdel %APPDATA%\bb\config.jsonbb auth login4002 - CONFIG_WRITE_FAILED
Section titled “4002 - CONFIG_WRITE_FAILED”Message: Cannot write config file
Cause: No write permission to the config directory.
Solution:
- Check directory permissions
- Ensure the parent directory exists
- On shared systems, verify you own the config directory
4003 - CONFIG_INVALID_KEY
Section titled “4003 - CONFIG_INVALID_KEY”Message: Invalid configuration key
Cause: Attempted to get or set an unknown configuration key.
Solution: Use a valid key. bb config set accepts six:
| Key | Meaning |
|---|---|
defaultWorkspace |
Workspace used when -w is omitted |
credentialStorage |
Where account secrets live: file or keychain |
skipVersionCheck |
Disable update notifications |
versionCheckInterval |
Days between update checks |
prCreateIncludeDefaultReviewers |
Add the repository’s default reviewers on bb pr create |
gitProtocol |
ssh or https for bb repo clone and fork fetches in bb pr checkout |
bb config get accepts those six plus username.
bb config set defaultWorkspace myworkspacebb config get usernamebb config listTwo keys get a distinct message instead of the unknown-key one. bb config set username and bb config set apiToken point you at bb auth login; bb config get apiToken points you at bb auth token. Every other credential field
(oauthAccessToken and friends) is not a config key at all and falls through to
the unknown-key message above.
Validation errors (5xxx)
Section titled “Validation errors (5xxx)”5001 - VALIDATION_REQUIRED
Section titled “5001 - VALIDATION_REQUIRED”Message: Required field missing
Cause: A required option or argument was not provided.
Solution: Check command help for required options:
bb <command> --helpCommon required fields:
bb pr createrequires--titlebb repo createrequires a name argument
5002 - VALIDATION_INVALID
Section titled “5002 - VALIDATION_INVALID”Message: Invalid value
Cause: A provided value doesn’t match expected format, or an unknown top-level command was given.
Solution:
- Check the expected format in command help
- Common issues:
- Pull request ID must be a number
- State must be one of: OPEN, MERGED, DECLINED, SUPERSEDED
- An unknown command (
bb prr) --jsonplaced before the subcommand, so it ate the subcommand as its field list; see Troubleshooting
Argument-parsing errors (an unknown option or subcommand, too many arguments)
are 5002 too, and a missing argument or option value is 5001. With --json
or --jq before any -- they come back as an envelope with
context.parseError (unknownOption, unknownCommand, excessArguments,
missingArgument, missingSubcommand, …), context.commandPath, and a hint naming the help
page:
bb pr list --stat --json# {"name":"BBError","code":5002,"message":"unknown option '--stat'","context":{"parseError":"unknownOption","commandPath":"pr list"},"hint":"Run `bb pr list --help` for usage."}The misplaced---json case names the token it swallowed. Because --json did
take effect, it comes back as an error envelope on stderr:
bb --json pr list{ "name": "BBError", "code": 5002, "message": "--json consumed 'pr' as its field list, so 'list' was parsed as a top-level command.\nPut --json after the subcommand: bb pr list --json", "context": { "command": "pr", "args": ["list"] }}When a value or name is close to a valid one, the CLI suggests the correction.
This fires for unknown commands, enum option values, config keys, bb pr activity --type tokens, and bb api HTTP methods:
bb prr# ✗ unknown command 'prr'# (Did you mean pr?)
bb pr list --state opne# ✗ --state must be one of: OPEN, MERGED, DECLINED, SUPERSEDED# (Did you mean OPEN?)
bb config set defaultWorkspce foo# ✗ Unknown config key 'defaultWorkspce'. Valid keys: defaultWorkspace, credentialStorage, skipVersionCheck, versionCheckInterval, prCreateIncludeDefaultReviewers, gitProtocol# (Did you mean defaultWorkspace?)Enum values ignore case, so --state open is accepted as OPEN.
5003 - FILE_NOT_FOUND
Section titled “5003 - FILE_NOT_FOUND”Message: File not found: <path>
Cause: A file referenced by an option (--file on bb snippet create/edit,
--body-file on bb pr create/edit or bb pr comments add/reply, -F key=@file or --input on
bb api) doesn’t exist on disk, or a named file isn’t present inside a snippet.
Solution:
- Verify the path is correct relative to the current working directory
- For
bb snippet view --file <name>, list snippet files first to confirm the name
The context field carries the offending path, so scripts can tell this apart
from a generic VALIDATION_INVALID. The key depends on the command:
| Key | Set by |
|---|---|
file |
bb snippet create/edit/view |
bodyFile |
--body-file on bb pr create/edit and bb pr comments add/reply |
path |
bb api -F key=@file, bb api --input <file> |
bb snippet view --file also attaches available, the list of filenames the
snippet actually contains.
--body-file only reports 5003 when the read failed with ENOENT.
Any other read failure (a permission error, or pointing at a directory) is
reported as 9999 UNKNOWN.
5004 - PROMPT_CANCELLED
Section titled “5004 - PROMPT_CANCELLED”Message: Cancelled. (a declined confirmation) or Prompt cancelled.
(Ctrl+C or Ctrl+D at any prompt)
Cause: You answered no at a Continue? (y/N) confirmation, or interrupted
an interactive prompt. Prompts only appear in an interactive terminal, so
scripts and CI never see this code. See
--no-input.
The process exits with status 1, except after Ctrl+C, which exits with 130 like any other interrupted command.
Solution:
- Run the command again and answer
y, or pass--yesto skip the question
5005 - CONFIRMATION_REQUIRED
Section titled “5005 - CONFIRMATION_REQUIRED”Message: <warning> followed by Use --yes to confirm.
Cause: A destructive command (repo delete, pr comments delete,
webhook delete, …) ran without --yes where it could not ask: a pipe, CI,
--json, or --no-input.
Solution: Rerun with --yes. context.retry holds the command with
--yes added, quoted for POSIX shells on macOS and Linux and for PowerShell on
Windows (cmd.exe is not supported):
bb repo delete acme/old-site --json{ "name": "BBError", "code": 5005, "message": "This will permanently delete acme/old-site.\nUse --yes to confirm.", "context": { "retry": "bb repo delete acme/old-site --json --yes" }}Before this code existed the same failure used 5001.
Context errors (6xxx)
Section titled “Context errors (6xxx)”6001 - CONTEXT_REPO_NOT_FOUND
Section titled “6001 - CONTEXT_REPO_NOT_FOUND”Message: Depends on the missing context: Not in a git repository.,
Git repository has no remote configured., or Remote … is not a Bitbucket URL.,
followed by instructions to supply --workspace and --repo.
Cause: The CLI could not resolve a Bitbucket repository. JSON errors include
context.reason and, when available, context.remoteUrl.
Solution:
- Use explicit flags:
bb pr list -w myworkspace -r myrepo- Supply both values outside a checkout; a default workspace alone does not identify a repository.
- Run from within a cloned Bitbucket repository
See Understanding Repository Context for details.
6002 - CONTEXT_WORKSPACE_NOT_FOUND
Section titled “6002 - CONTEXT_WORKSPACE_NOT_FOUND”Message: Could not determine workspace
Cause: The CLI couldn’t figure out which workspace to use.
Solution:
- Use the
-wflag:
bb repo list -w myworkspace- Set a default workspace:
bb config set defaultWorkspace myworkspaceNetwork errors (7xxx)
Section titled “Network errors (7xxx)”7001 - NETWORK_ERROR
Section titled “7001 - NETWORK_ERROR”Cause: The request failed before an HTTP response was received (offline, DNS issue, proxy/TLS issue, etc.).
Transient failures (dropped connections, temporary DNS errors, timeouts) on read requests are automatically retried up to 3 times with exponential backoff before this error surfaces. Permanent-looking failures (e.g. unknown host, connection refused) and write requests fail immediately.
7001 has two distinct messages. The connectivity one:
Network error: Unable to reach Bitbucket API. Run with BB_DEBUG=http for details. If you’re behind a proxy or using a custom CA, check your environment.
And the timeout one, when the server accepted the connection but never answered:
Network error: Request to Bitbucket API timed out after 30000ms. The server accepted the connection but did not respond in time. Increase or disable the timeout via BB_HTTP_TIMEOUT (milliseconds; set BB_HTTP_TIMEOUT=0 to disable), or run with BB_DEBUG=http for details.
Solution:
- Check internet and DNS connectivity
- Verify proxy/TLS settings if applicable
- If the message says timed out, raise or remove the 30-second default:
BB_HTTP_TIMEOUT=60000 bb pr list # 60 secondsBB_HTTP_TIMEOUT=0 bb pr list # no timeoutSee Environment Variables for the full list.
Output formatting errors (8xxx)
Section titled “Output formatting errors (8xxx)”8001 - JQ_FAILED
Section titled “8001 - JQ_FAILED”Message: jq evaluation failed: <jq compiler error>
Cause: The expression passed to --jq is invalid or produced a runtime error.
Solution:
- Test the expression interactively against the full output first:
bb pr list --json | jq '<expression>'- The embedded jq is jq 1.8.x; module imports (
include,import) are not supported. - Remember
--jqruns after field projection; when combined with--json fields, the input is already a flat array (the wrapper has been dropped).
8002 - JSON_FORMAT_INVALID
Section titled “8002 - JSON_FORMAT_INVALID”8002 covers flag combinations that can’t work and an empty field list.
--jq requires --json (or --lean requires --json); add --json,
with or without a field list:
bb pr list --json --jq '.count'bb api is exempt, because its output is already JSON: bb api /repositories/my-ws --jq '.values[].name' needs no --json.
--jq and --lean signal that you want machine-readable output, so this
error is a JSON envelope on stderr even though --json is missing.
--raw-output requires --jq; --raw-output only changes how --jq
prints strings, so pass a --jq expression with it.
--json field list cannot be empty; triggered by --json "" or --json ,,,.
Drop the argument to get the full output, or name at least one field:
bb pr list --jsonbb pr list --json id,titleShell completion errors (9001–9002)
Section titled “Shell completion errors (9001–9002)”9001 - COMPLETION_INSTALL_FAILED
Section titled “9001 - COMPLETION_INSTALL_FAILED”Message: Failed to install completions: <reason>
Cause: bb completion install couldn’t write the shell completion hooks; typically because the target shell profile isn’t writable, or the underlying tabtab install failed.
Solution:
- Check write permissions on your shell rc file (e.g.
~/.zshrc,~/.bashrc) - If the issue persists, install completions manually by following your shell’s documentation for
tabtab
9002 - COMPLETION_UNINSTALL_FAILED
Section titled “9002 - COMPLETION_UNINSTALL_FAILED”Message: Failed to uninstall completions: <reason>
Cause: bb completion uninstall couldn’t remove the completion hooks; usually because the rc file isn’t writable or the entry was already removed manually.
Solution:
- Check write permissions on your shell rc file
- Manually remove the
tabtabblock from your shell rc file if needed
CI outcome errors (10001)
Section titled “CI outcome errors (10001)”10001 - CI_FAILED
Section titled “10001 - CI_FAILED”Message: Pipeline #42 finished with status FAILED. or 1 check did not pass on pull request #7: build.
Cause: bb pipeline watch saw the run end without passing (failed, stopped, error, expired) or pause on a manual step, or bb pr checks --watch saw a check end as failed or stopped, or no check was reported at all. The command still prints the final state first; with --json the state goes to stdout and this error to stderr.
Solution:
bb pipeline logs 42 --step 2 # read the failing stepbb pr checks 7 # see which check failedUnknown errors (9999)
Section titled “Unknown errors (9999)”9999 - UNKNOWN
Section titled “9999 - UNKNOWN”Message: An unexpected error occurred
Cause: The CLI encountered an error that doesn’t fit any known category.
Solution:
- Check the error message for details
- Retry the command
- If the issue persists, report it with full debug output:
BB_DEBUG=verbose bb <your-command> 2>&1Exit codes and error codes
Section titled “Exit codes and error codes”0 on success, normally 1 on failure, and 130 for Ctrl+C at a prompt.
Set BB_DETAILED_EXIT_CODES to any non-empty value to get a status per failure
class instead. It is opt-in so scripts that compare $? against 1 keep
working:
| Status | Meaning | Error codes |
|---|---|---|
0 |
Success | |
1 |
Any other failure | everything not listed below |
2 |
Usage error | 4003, 5001, 5002, 5003, 6001, 6002, 8002, argument-parsing errors |
3 |
Not found | 2002 (any 404, including a missing diff or log) |
4 |
Authentication needed | 1001, 1002, 1003 |
5 |
Confirmation required | 5005 |
130 |
Ctrl+C at a prompt | 5004 after an interrupt |
export BB_DETAILED_EXIT_CODES=1bb pr view 999 --json 2> err.jsoncase $? in 0) ;; 3) echo "no such PR" ;; 4) echo "run bb auth login" ;; *) jq -r '.message' err.json ;;esacA 403 (2003) stays 1: it can mean a missing scope or a repository
permission, so read code and hint for it.
The exit status never carries the full error code; read it from the stderr payload instead:
bb pr view 999 --json 2> err.json || jq -r '.code' err.json# 2002That payload is a single-line JSON object:
{ "name": "APIError", "code": 2002, "message": "Pull request 999 not found in acme/demo.", "context": { "status": 404, "method": "GET", "url": "/repositories/acme/demo/pullrequests/999" }, "statusCode": 404}See Exit Codes in the scripting guide for a
worked example, and JSON Output for every payload
field and the context shape per code.
Handling errors in scripts
Section titled “Handling errors in scripts”Keep stdout and stderr on separate files. Folding stderr into the data file
(> prs.json 2>&1) puts the error envelope; and any warning the CLI prints;
inside prs.json, which breaks jq on the next line.
#!/bin/bashset -euo pipefail
if ! bb pr list -w myworkspace -r myrepo --json > prs.json 2> pr-error.json; then echo "Failed to list PRs: $(jq -r '.message // "unknown error"' pr-error.json)" exit 1fi
jq -r '.pullRequests[].title' prs.json