infiniflow/ragflow · critical · ConnectorMissingCredentialError
Bitbucket
Error message
Bitbucket
What it means
BitbucketConnector.load_credentials raises ConnectorMissingCredentialError('Bitbucket') when either bitbucket_email or bitbucket_api_token is absent/empty from the credentials dict.
Source
Thrown at common/data_source/bitbucket/connector.py:93
projects: str | None = None,
batch_size: int = INDEX_BATCH_SIZE,
) -> None:
self.workspace = workspace
self._repositories = [s.strip() for s in repositories.split(",") if s.strip()] if repositories else None
self._projects: list[str] | None = [s.strip() for s in projects.split(",") if s.strip()] if projects else None
self.batch_size = batch_size
self.email: str | None = None
self.api_token: str | None = None
def load_credentials(self, credentials: dict[str, Any]) -> dict[str, Any] | None:
"""Load API token-based credentials.
Expects a dict with keys: `bitbucket_email`, `bitbucket_api_token`.
"""
self.email = credentials.get("bitbucket_email")
self.api_token = credentials.get("bitbucket_api_token")
if not self.email or not self.api_token:
raise ConnectorMissingCredentialError("Bitbucket")
return None
def _client(self) -> httpx.Client:
"""Build an authenticated HTTP client or raise if credentials missing."""
if not self.email or not self.api_token:
raise ConnectorMissingCredentialError("Bitbucket")
return build_auth_client(self.email, self.api_token)
def _iter_pull_requests_for_repo(
self,
client: httpx.Client,
repo_slug: str,
params: dict[str, Any] | None = None,
start_url: str | None = None,
on_page: Callable[[str | None], None] | None = None,
) -> Iterator[dict[str, Any]]:
base = f"https://api.bitbucket.org/2.0/repositories/{self.workspace}/{repo_slug}/pullrequests"
yield from paginate(View on GitHub (pinned to 554fb1133a)
Solutions
- Provide both keys: {'bitbucket_email': '<email>', 'bitbucket_api_token': '<app password>'}
- Check for whitespace-only values; the truthiness check fails on empty strings
- Use a Bitbucket app password / API token with repository read scope
Example fix
// before
conn.load_credentials({"bitbucket_email": "me@example.com"})
// after
conn.load_credentials({"bitbucket_email": "me@example.com", "bitbucket_api_token": "xxxx"}) Defensive patterns
Strategy: validation
Validate before calling
def valid_bitbucket_creds(creds: dict) -> bool:
return bool(creds.get("bitbucket_email")) and bool(creds.get("bitbucket_api_token"))
assert valid_bitbucket_creds(creds), "need bitbucket_email and bitbucket_api_token" Type guard
def is_bitbucket_cred_dict(x) -> bool:
"""True when x carries both required Bitbucket credential fields."""
return (
isinstance(x, dict)
and isinstance(x.get("bitbucket_email"), str) and x["bitbucket_email"].strip() != ""
and isinstance(x.get("bitbucket_api_token"), str) and x["bitbucket_api_token"].strip() != ""
) Try / catch
try:
conn.load_credentials(creds)
except ConnectorMissingCredentialError:
creds = prompt_for_bitbucket_credentials() # refill missing keys
conn.load_credentials(creds) Prevention
- Validate credential dicts at config-save time with the exact key names
- Store both keys together in the secrets manager under one entry
- Strip whitespace when copying app passwords
When it happens
Trigger: Calling load_credentials with a dict missing 'bitbucket_email' or 'bitbucket_api_token', or where either value is an empty string/None.
Common situations: Storing the app password under a different key; blank form fields; secrets manager returning None on a missing entry.
Related errors
- main() must be defined or exported.
- Provided blob storage credentials appear invalid or expired.
- main() returned a non-JSON-serializable value.
- message.compileNotSupported
- Failed to delete memory
AI-assisted analysis of infiniflow/ragflow@554fb1133a (2026-08-15).
Data as JSON: /api/errors/663a16a1158d9cac.
Report an issue: GitHub.