{"record":{"id":"78ee9262d184dc87","repo":"infiniflow/ragflow","slug":"failed-to-initialise-azure-blob-client-exc","errorCode":null,"errorMessage":"Failed to initialise Azure Blob client: {exc}","messagePattern":"Failed to initialise Azure Blob client: (.+?)","errorType":"validation","errorClass":"ConnectorMissingCredentialError","httpStatus":null,"severity":"error","filePath":"common/data_source/azure_blob_connector.py","lineNumber":170,"sourceCode":"                    credential=account_key,\n                )\n                self._container_client = svc.get_container_client(container_name)\n            elif mode == \"sas_token\":\n                if not (container_url and sas_token):\n                    raise ConnectorMissingCredentialError(\"Azure Blob: container_url and sas_token are required for the sas_token auth mode\")\n                # mirrors RAGFlowAzureSasBlob; strip a leading \"?\" so we\n                # never produce a double-\"?\" that breaks SAS auth.\n                normalized_sas = str(sas_token).lstrip(\"?\")\n                full_url = f\"{container_url}?{normalized_sas}\"\n                self._container_client = ContainerClient.from_container_url(full_url)\n            else:\n                raise ConnectorMissingCredentialError(\n                    \"Azure Blob credentials are incomplete. Provide one of: (a) connection_string + container_name, (b) account_name + account_key + container_name, (c) container_url + sas_token.\"\n                )\n        except ConnectorMissingCredentialError:\n            raise\n        except Exception as exc:\n            raise ConnectorMissingCredentialError(f\"Failed to initialise Azure Blob client: {exc}\") from exc\n\n        return None\n\n    # ------------------------------------------------------------------\n    # Validation\n    # ------------------------------------------------------------------\n\n    def validate_connector_settings(self) -> None:\n        if self._container_client is None:\n            raise ConnectorMissingCredentialError(\"Azure Blob\")\n\n        try:\n            # get_container_properties() costs one API call; it returns\n            # the ETag and last-modified of the container, proving both\n            # the credential and the container name are valid.\n            self._container_client.get_container_properties()\n        except Exception as exc:\n            msg = str(exc)","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/common/data_source/azure_blob_connector.py#L152-L188","documentation":"Wraps any unexpected exception thrown while constructing the Azure SDK client objects in load_credentials (BlobServiceClient.from_connection_string, BlobServiceClient(...), or ContainerClient.from_container_url). The original exception is chained via 'from exc', so the full cause is preserved. ConnectorMissingCredentialError is used even though the root cause is usually a malformed credential value rather than a missing one.","triggerScenarios":"A credential value is present but malformed such that the azure SDK constructor throws: an unparseable connection string, an account_name containing illegal URL characters producing a bad account_url, or a SAS token/URL combination that from_container_url cannot parse. Deliberately raised ConnectorMissingCredentialErrors are re-raised untouched by the 'except ConnectorMissingCredentialError: raise' guard.","commonSituations":"Truncated connection string from a secrets manager, a connection string copied with smart quotes or a trailing newline, an account key with whitespace, or a version mismatch in azure-storage-blob changing constructor strictness.","solutions":["Inspect the chained exception (exc.__cause__) — it carries the exact SDK error","Validate the connection string format (must contain AccountName= and AccountKey= pairs) or re-copy the value from the Azure portal","Trim whitespace/newlines from all credential values before passing them in","Pin/upgrade azure-storage-blob to the connector's tested version"],"exampleFix":"# before\ncreds = {\"connection_string\": conn_str_from_env_with_trailing_newline, ...}\n\n# after\ncreds = {\n  \"connection_string\": conn_str_from_env.strip(),\n  \"container_name\": \"my-container\",\n}\nconnector.load_credentials(creds)","handlingStrategy":"try-catch","validationCode":"def clean_azure_creds(creds: dict) -> dict:\n    out = {k: v.strip() if isinstance(v, str) else v for k, v in creds.items()}\n    if \"connection_string\" in out and \"AccountName=\" not in out[\"connection_string\"]:\n        raise ValueError(\"connection_string does not look like an Azure connection string\")\n    return out","typeGuard":null,"tryCatchPattern":"try:\n    connector.load_credentials(creds)\nexcept ConnectorMissingCredentialError as e:\n    cause = e.__cause__\n    logger.error(\"azure client init failed: %s\", cause)\n    # distinguish wrap (523) from explicit raises by checking __cause__ presence\n    if cause is None:\n        raise ConfigError(str(e)) from e\n    raise TransientOrFormatError(str(cause)) from e","preventionTips":["Strip whitespace/newlines from every credential string before passing it in","Always inspect __cause__ on wrapped connector errors — the SDK message is the real diagnosis","Round-trip secrets through a checksum to detect truncation by env vars or secret managers"],"tags":["azure","azure-blob","sdk","credentials","exception-chaining"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}