{"record":{"id":"07012834930fb5a3","repo":"infiniflow/ragflow","slug":"azure-blob-insufficient-permissions-on-container","errorCode":null,"errorMessage":"Azure Blob: insufficient permissions on container: {msg[:300]}","messagePattern":"Azure Blob: insufficient permissions on container: (.+?)","errorType":"validation","errorClass":"InsufficientPermissionsError","httpStatus":null,"severity":"error","filePath":"common/data_source/azure_blob_connector.py","lineNumber":193,"sourceCode":"    # 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)\n            code = getattr(getattr(exc, \"error_code\", None), \"value\", None) or getattr(exc, \"error_code\", \"\")\n            if \"AuthenticationFailed\" in msg or \"InvalidAuthenticationInfo\" in msg:\n                raise ConnectorMissingCredentialError(f\"Azure Blob credential rejected: {msg[:300]}\") from exc\n            if \"AuthorizationPermissionMismatch\" in msg or \"403\" in msg:\n                raise InsufficientPermissionsError(f\"Azure Blob: insufficient permissions on container: {msg[:300]}\") from exc\n            if \"ContainerNotFound\" in msg or \"404\" in msg:\n                raise ConnectorValidationError(f\"Azure Blob: container not found: {msg[:300]}\") from exc\n            raise UnexpectedValidationError(f\"Azure Blob validation failed ({code}): {msg[:300]}\") from exc\n\n    # ------------------------------------------------------------------\n    # Checkpoint helpers\n    # ------------------------------------------------------------------\n\n    def build_dummy_checkpoint(self) -> AzureBlobCheckpoint:\n        return AzureBlobCheckpoint(has_more=True)\n\n    def validate_checkpoint_json(self, checkpoint_json: str) -> AzureBlobCheckpoint:\n        try:\n            return AzureBlobCheckpoint.model_validate_json(checkpoint_json)\n        except Exception:\n            return self.build_dummy_checkpoint()\n\n    # ------------------------------------------------------------------","sourceCodeStart":175,"sourceCodeEnd":211,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/common/data_source/azure_blob_connector.py#L175-L211","documentation":"Raised by validate_connector_settings when get_container_properties() returns an authorization failure that is not an authentication failure — the credential is valid but lacks permission on this container. Azure's 'AuthorizationPermissionMismatch' or any 403 without the auth-failed signature maps to InsufficientPermissionsError.","triggerScenarios":"Account key or SAS token authenticates correctly but has no RBAC role / SAS permission to read container properties: e.g. a service principal with no 'Storage Blob Data Reader' role, or a SAS token lacking the List permission (container-level read of properties requires appropriate scope).","commonSituations":"Least-privilege SAS tokens issued without the 'container' permission bit, service principals granted roles at the wrong scope (subscription instead of the storage account/container), or Azure RBAC propagation delay after a role assignment.","solutions":["For SAS: reissue the token with read + list permissions at container scope","For service-principal/account-key setups: grant 'Storage Blob Data Reader' (or Contributor) at the storage account or container scope and wait for RBAC propagation (can take minutes)","Verify the error body (included, truncated to 300 chars) confirms AuthorizationPermissionMismatch rather than AuthenticationFailed — the fix differs"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"# Nothing local can prove RBAC; a dry-run listing is the practical pre-check:\ntry:\n    client.get_container_properties()\nexcept Exception as e:\n    if \"AuthorizationPermissionMismatch\" in str(e):\n        raise PermissionError(\"grant Storage Blob Data Reader before ingest\") from e","typeGuard":null,"tryCatchPattern":"try:\n    connector.validate_connector_settings()\nexcept InsufficientPermissionsError as e:\n    # credential valid but under-privileged: alert infra owner, don't retry\n    alert_ops(f\"Azure RBAC missing for connector: {e}\")\n    raise","preventionTips":["Grant 'Storage Blob Data Reader' at container/account scope as part of connector provisioning","Include a validation step in deployment that runs validate_connector_settings before enabling schedules","After role assignment, allow for RBAC propagation delay before re-validating"],"tags":["azure","azure-blob","rbac","permissions","authorization"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}