{"record":{"id":"40f5afa9a01df03d","repo":"infiniflow/ragflow","slug":"invalid-or-expired-bitbucket-credentials-http-401","errorCode":null,"errorMessage":"Invalid or expired Bitbucket credentials (HTTP 401).","messagePattern":"Invalid or expired Bitbucket credentials \\(HTTP 401\\)\\.","errorType":"validation","errorClass":"CredentialExpiredError","httpStatus":401,"severity":"critical","filePath":"common/data_source/bitbucket/connector.py","lineNumber":299,"sourceCode":"\n    def validate_connector_settings(self) -> None:\n        \"\"\"Validate Bitbucket credentials and workspace access by probing a lightweight endpoint.\n\n        Raises:\n            CredentialExpiredError: on HTTP 401\n            InsufficientPermissionsError: on HTTP 403\n            UnexpectedValidationError: on any other failure\n        \"\"\"\n        try:\n            with self._client() as client:\n                url = f\"https://api.bitbucket.org/2.0/repositories/{self.workspace}\"\n                resp = client.get(\n                    url,\n                    params={\"pagelen\": 1, \"fields\": \"pagelen\"},\n                    timeout=REQUEST_TIMEOUT_SECONDS,\n                )\n                if resp.status_code == 401:\n                    raise CredentialExpiredError(\"Invalid or expired Bitbucket credentials (HTTP 401).\")\n                if resp.status_code == 403:\n                    raise InsufficientPermissionsError(\"Insufficient permissions to access Bitbucket workspace (HTTP 403).\")\n                if resp.status_code < 200 or resp.status_code >= 300:\n                    raise UnexpectedValidationError(f\"Unexpected Bitbucket error (status={resp.status_code}).\")\n        except Exception as e:\n            # Network or other unexpected errors\n            if isinstance(\n                e,\n                (\n                    CredentialExpiredError,\n                    InsufficientPermissionsError,\n                    UnexpectedValidationError,\n                    ConnectorMissingCredentialError,\n                ),\n            ):\n                raise\n            raise UnexpectedValidationError(f\"Unexpected error while validating Bitbucket settings: {e}\")\n","sourceCodeStart":281,"sourceCodeEnd":317,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/common/data_source/bitbucket/connector.py#L281-L317","documentation":"During settings validation, a GET to https://api.bitbucket.org/2.0/repositories/{workspace} returning HTTP 401 maps to CredentialExpiredError: the email/app-password pair was rejected by Bitbucket.","triggerScenarios":"Revoked or mistyped app password, wrong email (Bitbucket requires the account username/email associated with the token), or a token from a different account.","commonSituations":"App password regenerated in Bitbucket settings but old value still stored; using the workspace name instead of the account email; SSO-managed accounts with rotated credentials.","solutions":["Create/confirm an app password in Bitbucket Personal Settings → App passwords with account/repo read scope","Update stored bitbucket_api_token and verify bitbucket_email matches the token owner","Re-run validate_connector_settings after updating"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    conn.validate_connector_settings()\nexcept CredentialExpiredError:\n    notify_user_credentials_expired()   # surface re-auth prompt\n    creds = refresh_bitbucket_app_password()\n    conn.load_credentials(creds)\n    conn.validate_connector_settings()","preventionTips":["Treat app passwords as rotatable secrets with a refresh path in the UI","Surface a clear 're-authenticate' action on CredentialExpiredError instead of a generic failure","Store tokens with creation dates and remind users before likely rotation"],"tags":["bitbucket","http-401","credentials","expired-token"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}