{"record":{"id":"663a16a1158d9cac","repo":"infiniflow/ragflow","slug":"bitbucket","errorCode":null,"errorMessage":"Bitbucket","messagePattern":"Bitbucket","errorType":"validation","errorClass":"ConnectorMissingCredentialError","httpStatus":null,"severity":"critical","filePath":"common/data_source/bitbucket/connector.py","lineNumber":93,"sourceCode":"        projects: str | None = None,\n        batch_size: int = INDEX_BATCH_SIZE,\n    ) -> None:\n        self.workspace = workspace\n        self._repositories = [s.strip() for s in repositories.split(\",\") if s.strip()] if repositories else None\n        self._projects: list[str] | None = [s.strip() for s in projects.split(\",\") if s.strip()] if projects else None\n        self.batch_size = batch_size\n        self.email: str | None = None\n        self.api_token: str | None = None\n\n    def load_credentials(self, credentials: dict[str, Any]) -> dict[str, Any] | None:\n        \"\"\"Load API token-based credentials.\n\n        Expects a dict with keys: `bitbucket_email`, `bitbucket_api_token`.\n        \"\"\"\n        self.email = credentials.get(\"bitbucket_email\")\n        self.api_token = credentials.get(\"bitbucket_api_token\")\n        if not self.email or not self.api_token:\n            raise ConnectorMissingCredentialError(\"Bitbucket\")\n        return None\n\n    def _client(self) -> httpx.Client:\n        \"\"\"Build an authenticated HTTP client or raise if credentials missing.\"\"\"\n        if not self.email or not self.api_token:\n            raise ConnectorMissingCredentialError(\"Bitbucket\")\n        return build_auth_client(self.email, self.api_token)\n\n    def _iter_pull_requests_for_repo(\n        self,\n        client: httpx.Client,\n        repo_slug: str,\n        params: dict[str, Any] | None = None,\n        start_url: str | None = None,\n        on_page: Callable[[str | None], None] | None = None,\n    ) -> Iterator[dict[str, Any]]:\n        base = f\"https://api.bitbucket.org/2.0/repositories/{self.workspace}/{repo_slug}/pullrequests\"\n        yield from paginate(","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/common/data_source/bitbucket/connector.py#L75-L111","documentation":"BitbucketConnector.load_credentials raises ConnectorMissingCredentialError('Bitbucket') when either bitbucket_email or bitbucket_api_token is absent/empty from the credentials dict.","triggerScenarios":"Calling load_credentials with a dict missing 'bitbucket_email' or 'bitbucket_api_token', or where either value is an empty string/None.","commonSituations":"Storing the app password under a different key; blank form fields; secrets manager returning None on a missing entry.","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"],"exampleFix":"// before\nconn.load_credentials({\"bitbucket_email\": \"me@example.com\"})\n\n// after\nconn.load_credentials({\"bitbucket_email\": \"me@example.com\", \"bitbucket_api_token\": \"xxxx\"})","handlingStrategy":"validation","validationCode":"def valid_bitbucket_creds(creds: dict) -> bool:\n    return bool(creds.get(\"bitbucket_email\")) and bool(creds.get(\"bitbucket_api_token\"))\n\nassert valid_bitbucket_creds(creds), \"need bitbucket_email and bitbucket_api_token\"","typeGuard":"def is_bitbucket_cred_dict(x) -> bool:\n    \"\"\"True when x carries both required Bitbucket credential fields.\"\"\"\n    return (\n        isinstance(x, dict)\n        and isinstance(x.get(\"bitbucket_email\"), str) and x[\"bitbucket_email\"].strip() != \"\"\n        and isinstance(x.get(\"bitbucket_api_token\"), str) and x[\"bitbucket_api_token\"].strip() != \"\"\n    )","tryCatchPattern":"try:\n    conn.load_credentials(creds)\nexcept ConnectorMissingCredentialError:\n    creds = prompt_for_bitbucket_credentials()  # refill missing keys\n    conn.load_credentials(creds)","preventionTips":["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"],"tags":["bitbucket","credentials","authentication","validation"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}