cocoindex-io/cocoindex · error · ValueError

Azure Blob container client must expose account_name and…

Error message

Azure Blob container client must expose account_name and container_name, or a URL containing both.

What it means

To build S3-style object identifiers, the Azure Blob connector needs to know the storage account name and container name. _container_identity tries client.account_name/client.container_name attributes, then falls back to parsing the client's URL; if neither source yields both names it raises this ValueError.

Solutions

  1. Construct the ContainerClient with account_url in the standard form https://<account>.blob.core.windows.net so the URL contains both account and container.
  2. Ensure the client object exposes account_name and container_name attributes (the Azure SDK ContainerClient does).
  3. In tests, add account_name/container_name attributes to your mock client.
  4. If using Azurite, use a URL like http://127.0.0.1:10000/devstoreaccount1/<container> that includes the account name.

Example fix

// before
client = ContainerClient(account_url="https://mystorage.blob.core.windows.net/custompath", container_name="docs")
blob = await azure_blob.get_blob(client, "file.txt")  # may fail if identity can't be derived

// after
client = ContainerClient(account_url="https://mystorage.blob.core.windows.net", container_name="docs")
blob = await azure_blob.get_blob(client, "file.txt")
Defensive patterns

Strategy: type-guard

Validate before calling

def has_container_identity(client) -> bool:
    if getattr(client, "account_name", None) and getattr(client, "container_name", None):
        return True
    url = getattr(client, "url", "") or ""
    return ".blob.core.windows.net" in url and bool(getattr(client, "container_name", None))

Type guard

def usable_container_client(client: object) -> bool:
    return hasattr(client, "account_name") and hasattr(client, "container_name")

Try / catch

try:
    blob = await azure_blob.get_blob(client, name)
except ValueError as e:
    logger.error("container client lacks identity: %s", e)
    raise

Prevention

When it happens

Trigger: Calling get_blob (or constructing the source connector whose __init__ calls _container_identity) with a ContainerClient that was built from a connection string or custom endpoint lacking account/container in its URL, or a mock/stub client without those attributes or a standard URL.

Common situations: Custom domain or Azurite/emulator endpoints where the URL doesn't embed the account name; hand-rolled fakes in tests without account_name/container_name attributes; using a raw URL-based client with an unusual hostname.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of cocoindex-io/cocoindex@e84aa99b32 (2026-09-08). Data as JSON: /api/errors/3cf52ded5e0bb3ef. Report an issue: GitHub.

Appendix: source

Thrown at python/cocoindex/connectors/azure_blob/_source.py:100

    url = _text_attr(client, "url")
    if url is None:
        return None, None

    parsed = urlparse(url)
    account_name = parsed.netloc.split(".", 1)[0] if parsed.netloc else None
    path_parts = [part for part in parsed.path.split("/") if part]
    container_name = path_parts[0] if path_parts else None
    return account_name, container_name


def _container_identity(client: _ContainerClient) -> tuple[str, str]:
    account_name = _text_attr(client, "account_name")
    container_name = _text_attr(client, "container_name")
    url_account_name, url_container_name = _identity_from_url(client)
    account_name = account_name or url_account_name
    container_name = container_name or url_container_name
    if account_name is None or container_name is None:
        raise ValueError(
            "Azure Blob container client must expose account_name and "
            "container_name, or a URL containing both."
        )
    return account_name, container_name


def _metadata_from_properties(props: _BlobProperties) -> file.FileMetadata:
    return file.FileMetadata(
        size=int(props.size),
        modified_time=props.last_modified,
        content_fingerprint=_etag_to_fingerprint(props.etag),
    )


def _get_blob_client(
    container_client: _ContainerClient,
    blob_name: str,
) -> _BlobClient:

View on GitHub (pinned to e84aa99b32)