{"record":{"id":"a6d45f7a8dfebca1","repo":"github/spec-kit","slug":"providers-i-field-name-must-be-a-non-empty","errorCode":null,"errorMessage":"providers[{i}]: '{field_name}' must be a non-empty string","messagePattern":"providers\\[(.+?)\\]: '(.+?)' must be a non-empty string","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/specify_cli/authentication/config.py","lineNumber":198,"sourceCode":"                raise ValueError(\n                    f\"providers[{i}]: auth={auth!r} requires 'token' or 'token_env'\"\n                )\n        elif auth == \"azure-ad\":\n            tenant_id = entry_raw.get(\"tenant_id\")\n            client_id = entry_raw.get(\"client_id\")\n            client_secret_env = entry_raw.get(\"client_secret_env\")\n            if not all([tenant_id, client_id, client_secret_env]):\n                raise ValueError(\n                    f\"providers[{i}]: auth='azure-ad' requires \"\n                    \"'tenant_id', 'client_id', and 'client_secret_env'\"\n                )\n            for field_name, field_val in [\n                (\"tenant_id\", tenant_id),\n                (\"client_id\", client_id),\n                (\"client_secret_env\", client_secret_env),\n            ]:\n                if not isinstance(field_val, str) or not field_val.strip():\n                    raise ValueError(\n                        f\"providers[{i}]: '{field_name}' must be a non-empty string\"\n                    )\n        # azure-cli needs no extra fields\n\n        entries.append(\n            AuthConfigEntry(\n                hosts=tuple(hosts),\n                provider=provider,\n                auth=auth,\n                token=token,\n                token_env=_norm(token_env),\n                tenant_id=_norm(entry_raw.get(\"tenant_id\")),\n                client_id=_norm(entry_raw.get(\"client_id\")),\n                client_secret_env=_norm(entry_raw.get(\"client_secret_env\")),\n            )\n        )\n\n    return entries","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/github/spec-kit/blob/bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c/src/specify_cli/authentication/config.py#L180-L216","documentation":"Follow-up guard for `auth: azure-ad`: after the presence check, each of `tenant_id`, `client_id`, `client_secret_env` is verified to be a non-empty, non-whitespace string. It reports the exact offending field name in the message.","triggerScenarios":"One of the three azure-ad fields is a non-string type (e.g. an int tenant/client id from unquoted YAML) or a whitespace-only string; the presence check at :188 only catches falsy values, so `tenant_id: 12345` passes it and fails here.","commonSituations":"Azure tenant IDs and client (app) IDs are long digit/UUID strings; unquoted numeric IDs parse as ints in YAML and then fail this isinstance check.","solutions":["Quote the value so YAML parses it as a string: `tenant_id: \"12345678-...\"`","Check the field named in the error message specifically","Trim accidental whitespace-only values"],"exampleFix":"# before\ntenant_id: 12345678-1234-1234-1234-123456789012   # may parse oddly or be blank\n\n# after\ntenant_id: \"12345678-1234-1234-1234-123456789012\"","handlingStrategy":"validation","validationCode":"for k in (\"tenant_id\", \"client_id\", \"client_secret_env\"):\n    v = entry.get(k)\n    if v is not None and not (isinstance(v, str) and v.strip()):\n        raise SystemExit(f\"{k} must be a quoted non-empty string (YAML parses bare digits as int)\")","typeGuard":"def azure_fields_are_strings(entry: dict) -> bool:\n    return all(entry.get(k) is None or isinstance(entry.get(k), str)\n               for k in (\"tenant_id\", \"client_id\", \"client_secret_env\"))","tryCatchPattern":"try:\n    load_auth_config(raw)\nexcept ValueError as exc:\n    if \"must be a non-empty string\" in str(exc) and entry.get(\"auth\") == \"azure-ad\":\n        # quote the offending field named in the message and reload\n        raise\n    raise","preventionTips":["Quote all Azure IDs in YAML — UUID/numeric-looking values parse as non-strings otherwise","Use str() coercion when generating the config programmatically"],"tags":["authentication","azure","config","validation","yaml-quoting"],"backgroundTag":null,"analyzedSha":"bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c","analyzedAt":"2026-08-14T19:43:37.150Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}