{"record":{"id":"9aaa89a0d071adb0","repo":"infiniflow/ragflow","slug":"azure-blob-credentials-are-incomplete-provide-one","errorCode":null,"errorMessage":"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.","messagePattern":"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\\.","errorType":"validation","errorClass":"ConnectorMissingCredentialError","httpStatus":null,"severity":"error","filePath":"common/data_source/azure_blob_connector.py","lineNumber":164,"sourceCode":"                    raise ConnectorMissingCredentialError(\"Azure Blob: account_name and account_key are required for the account_key auth mode\")\n                if not container_name:\n                    raise ConnectorMissingCredentialError(\"Azure Blob: container_name is required together with account_name + account_key\")\n                account_url = f\"https://{account_name}.{_AZURE_ENDPOINT_SUFFIX}\"\n                svc = BlobServiceClient(\n                    account_url=account_url,\n                    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:","sourceCodeStart":146,"sourceCodeEnd":182,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/common/data_source/azure_blob_connector.py#L146-L182","documentation":"The catch-all for an unrecognized auth mode in the Azure Blob connector's load_credentials. The if/elif chain covers connection_string, account_key, and sas_token; anything else falls to the else branch and raises this message listing the three valid credential shapes. It is purely local — no network call happens.","triggerScenarios":"The mode variable computed from the credentials dict matches none of 'connection_string', 'account_key', 'sas_token' — e.g. an explicit 'auth_mode' key with a typo ('sas'), or a credential set that has none of the identifying key combinations so mode ends up as some sentinel/empty value.","commonSituations":"A stale config from an older connector version that used a different auth_mode naming, hand-edited YAML/JSON with 'mode: service_principal', or a completely empty credentials dict passed to load_credentials.","solutions":["Supply one of the three documented credential sets: (a) connection_string + container_name, (b) account_name + account_key + container_name, (c) container_url + sas_token","If you set an explicit mode key, correct its value to one of connection_string | account_key | sas_token","Log the credential KEYS (never values) before load_credentials to see which branch the mode resolver picked"],"exampleFix":"// before\ncreds = {\"tenant_id\": \"...\", \"client_secret\": \"...\"}  // unsupported shape\nconnector.load_credentials(creds)\n\n// after\ncreds = {\n  \"account_name\": \"myaccount\",\n  \"account_key\": \"<key>\",\n  \"container_name\": \"my-container\",\n}\nconnector.load_credentials(creds)","handlingStrategy":"validation","validationCode":"AZURE_MODES = {\"connection_string\", \"account_key\", \"sas_token\"}\ndef validate_azure_mode(creds: dict) -> None:\n    mode = creds.get(\"auth_mode\")\n    if mode is not None and mode not in AZURE_MODES:\n        raise ValueError(f\"unsupported auth_mode {mode!r}; expected one of {sorted(AZURE_MODES)}\")","typeGuard":"def has_any_supported_azure_shape(c: dict) -> bool:\n    return bool(c.get(\"connection_string\")) or is_complete_account_key_creds(c) or is_complete_sas_creds(c)","tryCatchPattern":"try:\n    connector.load_credentials(creds)\nexcept ConnectorMissingCredentialError as e:\n    # the message enumerates the three valid shapes; echo it verbatim to the user\n    raise ConfigError(str(e)) from e","preventionTips":["Fail fast on unknown auth_mode values at config-load time, not inside the connector","Maintain a schema (pydantic/jsonschema) for connector credentials and validate before submission","Log credential KEYS only when debugging to spot which shape was actually provided"],"tags":["azure","azure-blob","auth-mode","configuration","connector"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}