{"record":{"id":"51ca13dd4d930eb7","repo":"github/spec-kit","slug":"providers-i-token-must-be-a-non-empty-string","errorCode":null,"errorMessage":"providers[{i}]: 'token' must be a non-empty string","messagePattern":"providers\\[(.+?)\\]: 'token' must be a non-empty string","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/specify_cli/authentication/config.py","lineNumber":158,"sourceCode":"                    f\"providers[{i}]: invalid host pattern {h!r}. \"\n                    \"Only exact hostnames or '*.suffix' forms are allowed \"\n                    \"(e.g. 'github.com' or '*.visualstudio.com').\"\n                )\n\n        provider = entry_raw.get(\"provider\", \"\")\n        if not isinstance(provider, str) or not provider:\n            raise ValueError(f\"providers[{i}]: 'provider' must be a non-empty string\")\n\n        auth = entry_raw.get(\"auth\", \"\")\n        if not isinstance(auth, str) or not auth:\n            raise ValueError(f\"providers[{i}]: 'auth' must be a non-empty string\")\n\n        token = entry_raw.get(\"token\")\n        token_env = entry_raw.get(\"token_env\")\n\n        # Validate token/token_env types\n        if token is not None and (not isinstance(token, str) or not token.strip()):\n            raise ValueError(f\"providers[{i}]: 'token' must be a non-empty string\")\n        if token_env is not None and (not isinstance(token_env, str) or not token_env.strip()):\n            raise ValueError(f\"providers[{i}]: 'token_env' must be a non-empty string\")\n\n        # Validate provider+scheme compatibility\n        from . import get_provider as _get_provider\n        _prov = _get_provider(provider)\n        if _prov is None:\n            from . import AUTH_REGISTRY\n            raise ValueError(\n                f\"providers[{i}]: unknown provider {provider!r}; \"\n                f\"registered: {sorted(AUTH_REGISTRY.keys())}\"\n            )\n        if auth not in _prov.supported_auth_schemes:\n            raise ValueError(\n                f\"providers[{i}]: provider {provider!r} does not support \"\n                f\"auth scheme {auth!r}; supported: {list(_prov.supported_auth_schemes)}\"\n            )\n","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/github/spec-kit/blob/bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c/src/specify_cli/authentication/config.py#L140-L176","documentation":"Raised when a provider entry sets an explicit `token` that is either not a string or blank. `token` is optional (a `token_env` alternative exists), but if present it must be a non-empty, non-whitespace string.","triggerScenarios":"`\"token\": \"\"`, `\"token\": \"   \"`, `\"token\": null` handled? no — `null` means absent; the trigger is a non-None non-string or whitespace-only value, e.g. `\"token\": 12345` or `\"token\": \"\"`.","commonSituations":"Pasting a numeric PAT (some providers issue numeric tokens) so YAML parses it as an int; empty string left by an env-substitution placeholder that didn't expand; quoting issues in YAML.","solutions":["Quote the token in YAML/JSON so it is a string, e.g. `token: \"1234567890\"`","Remove the `token` key entirely if you meant to use `token_env` instead","Ensure any templating step actually produced a value rather than an empty string"],"exampleFix":"# before\ntoken: 1234567890abcdef   # parsed as int\ntoken: \"\"\n\n# after\ntoken: \"1234567890abcdef\"","handlingStrategy":"validation","validationCode":"token = entry.get(\"token\")\nif token is not None and (not isinstance(token, str) or not token.strip()):\n    raise SystemExit(\"token must be a non-empty string — quote it in YAML or use token_env\")","typeGuard":"def has_valid_token_source(entry: dict) -> bool:\n    token, token_env = entry.get(\"token\"), entry.get(\"token_env\")\n    token_ok = token is None or (isinstance(token, str) and token.strip())\n    env_ok = token_env is None or (isinstance(token_env, str) and token_env.strip())\n    return token_ok and env_ok and (token is not None or token_env is not None)","tryCatchPattern":"try:\n    load_auth_config(raw)\nexcept ValueError as exc:\n    if \"'token' must be a non-empty string\" in str(exc):\n        # quote the value or drop the key in favor of token_env\n        raise\n    raise","preventionTips":["Always quote token values in YAML so numeric PATs stay strings","Prefer token_env over inline token in checked-in configs"],"tags":["authentication","config","validation","secrets"],"backgroundTag":null,"analyzedSha":"bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c","analyzedAt":"2026-08-14T19:43:37.150Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}