github/spec-kit · error · ValueError

providers[{i}]: auth='azure-ad' requires 'tenant_id', 'clien

Error message

providers[{i}]: auth='azure-ad' requires 'tenant_id', 'client_id', and 'client_secret_env'

What it means

Raised for `auth: azure-ad` when any of `tenant_id`, `client_id`, or `client_secret_env` is missing/falsy in the provider entry. The Azure AD client-credentials flow needs all three, where the client secret is referenced indirectly through an environment variable name.

Source

Thrown at src/specify_cli/authentication/config.py:188

            )
        if auth not in _prov.supported_auth_schemes:
            raise ValueError(
                f"providers[{i}]: provider {provider!r} does not support "
                f"auth scheme {auth!r}; supported: {list(_prov.supported_auth_schemes)}"
            )

        # Validate token source based on auth scheme
        if auth in ("bearer", "basic-pat"):
            if not token and not token_env:
                raise ValueError(
                    f"providers[{i}]: auth={auth!r} requires 'token' or 'token_env'"
                )
        elif auth == "azure-ad":
            tenant_id = entry_raw.get("tenant_id")
            client_id = entry_raw.get("client_id")
            client_secret_env = entry_raw.get("client_secret_env")
            if not all([tenant_id, client_id, client_secret_env]):
                raise ValueError(
                    f"providers[{i}]: auth='azure-ad' requires "
                    "'tenant_id', 'client_id', and 'client_secret_env'"
                )
            for field_name, field_val in [
                ("tenant_id", tenant_id),
                ("client_id", client_id),
                ("client_secret_env", client_secret_env),
            ]:
                if not isinstance(field_val, str) or not field_val.strip():
                    raise ValueError(
                        f"providers[{i}]: '{field_name}' must be a non-empty string"
                    )
        # azure-cli needs no extra fields

        entries.append(
            AuthConfigEntry(
                hosts=tuple(hosts),
                provider=provider,

View on GitHub (pinned to bf88c9f9a8)

Solutions

  1. Set all three keys: `tenant_id`, `client_id`, `client_secret_env` (name of the env var holding the secret)
  2. Export the secret in the environment under the name given to `client_secret_env`
  3. If you only have a PAT, use `auth: basic-pat` with `token_env` instead of azure-ad

Example fix

# before
- hosts: ["*.visualstudio.com"]
  provider: azure-devops
  auth: azure-ad
  tenant_id: <tid>

# after
- hosts: ["*.visualstudio.com"]
  provider: azure-devops
  auth: azure-ad
  tenant_id: <tid>
  client_id: <cid>
  client_secret_env: AZURE_CLIENT_SECRET
Defensive patterns

Strategy: validation

Validate before calling

if entry.get("auth") == "azure-ad":
    missing = [k for k in ("tenant_id", "client_id", "client_secret_env") if not entry.get(k)]
    if missing:
        raise SystemExit(f"azure-ad entry missing: {missing}")

Type guard

def is_complete_azure_ad(entry: dict) -> bool:
    if entry.get("auth") != "azure-ad":
        return True
    return all(isinstance(entry.get(k), str) and entry[k].strip()
               for k in ("tenant_id", "client_id", "client_secret_env"))

Try / catch

try:
    load_auth_config(raw)
except ValueError as exc:
    if "auth='azure-ad' requires" in str(exc):
        # collect the three fields (e.g. via az ad sp create-for-rbac) and retry
        raise
    raise

Prevention

When it happens

Trigger: An `auth: azure-ad` entry where one or more of the keys `tenant_id`, `client_id`, `client_secret_env` are absent, `null`, or empty strings — the `all([...])` check treats falsy values as missing.

Common situations: Migrating a bearer entry to azure-ad and only adding `tenant_id`; putting the secret value in `client_secret` instead of `client_secret_env` (the library deliberately never stores the raw secret); Azure DevOps PAT setups that actually want `basic-pat`.

Related errors


AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14). Data as JSON: /api/errors/3351fe275cc5fed5. Report an issue: GitHub.