{"record":{"id":"67a0e6c2393350d3","repo":"invoke-ai/InvokeAI","slug":"failed-to-load-api-keys-file-api-keys-file-path-67a0e6","errorCode":null,"errorMessage":"Failed to load api keys file {api_keys_file_path}: value for '{field_name}' must be a string","messagePattern":"Failed to load api keys file (.+?): value for '(.+?)' must be a string","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"invokeai/app/services/config/config_default.py","lineNumber":659,"sourceCode":"    if not api_keys_file_path.exists():\n        return {}\n\n    with open(api_keys_file_path, \"rt\", encoding=locale.getpreferredencoding()) as file:\n        loaded_api_keys: Any = yaml.safe_load(file)\n\n    if loaded_api_keys is None:\n        return {}\n\n    if not isinstance(loaded_api_keys, dict):\n        raise RuntimeError(f\"Failed to load api keys file {api_keys_file_path}: expected a mapping\")\n\n    parsed_api_keys: dict[str, str] = {}\n    for field_name in EXTERNAL_PROVIDER_CONFIG_FIELDS:\n        value = loaded_api_keys.get(field_name)\n        if value is None:\n            continue\n        if not isinstance(value, str):\n            raise RuntimeError(\n                f\"Failed to load api keys file {api_keys_file_path}: value for '{field_name}' must be a string\"\n            )\n        stripped_value = value.strip()\n        if stripped_value:\n            parsed_api_keys[field_name] = stripped_value\n\n    return parsed_api_keys\n\n\n@lru_cache(maxsize=1)\ndef get_config() -> InvokeAIAppConfig:\n    \"\"\"Get the global singleton app config.\n\n    When first called, this function:\n    - Creates a config object. `pydantic-settings` handles merging of settings from environment variables, but not the init file.\n    - Retrieves any provided CLI args from the InvokeAIArgs class. It does not _parse_ the CLI args; that is done in the main entrypoint.\n    - Sets the root dir, if provided via CLI args.\n    - Logs in to HF if there is no valid token already.","sourceCodeStart":641,"sourceCodeEnd":677,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/services/config/config_default.py#L641-L677","documentation":"load_external_api_keys validates that every recognized external-provider field in the API keys YAML is a string. A recognized field_name present with a non-string YAML value (int, list, nested mapping) raises this RuntimeError.","triggerScenarios":"api_keys_file_path contains a key in EXTERNAL_PROVIDER_CONFIG_FIELDS whose value parses as a non-string, e.g. `openai: 12345`, `openai:\\n  - part1`.","commonSituations":"Unquoted API keys that YAML coerces (numeric-looking keys, keys starting with special chars), or a nested config accidentally pasted under a provider field.","solutions":["Quote the value in the YAML so it is a string: `openai: \"12345\"`","Flatten any nested structures under the provider field to a single string value","Re-run after checking each field name matches EXTERNAL_PROVIDER_CONFIG_FIELDS and maps to a plain string"],"exampleFix":"// before (api_keys.yml)\nopenai: 1234567890\n// after\n\nopenai: \"1234567890\"","handlingStrategy":"type-guard","validationCode":"import yaml\nfrom pathlib import Path\nfrom invokeai.app.services.config import EXTERNAL_PROVIDER_CONFIG_FIELDS\ndef all_values_strings(p: Path) -> bool:\n    data = yaml.safe_load(p.read_text()) or {}\n    return all(isinstance(data.get(f), str) for f in EXTERNAL_PROVIDER_CONFIG_FIELDS if f in data)","typeGuard":"def is_str_value(v: object) -> bool:\n    return isinstance(v, str)","tryCatchPattern":"try:\n    keys = load_external_api_keys(path)\nexcept RuntimeError as e:\n    logger.error(f\"api keys value type wrong: {e}\")\n    raise SystemExit(1)","preventionTips":["Quote every API key value in YAML, especially numeric-looking keys","Keep provider fields flat — never nest mappings or lists under them","Lint the keys file in CI with the all_values_strings check"],"tags":["config","yaml","type-error","api-keys"],"backgroundTag":"config-value-type-mismatch","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}