{"record":{"id":"202c8ab7059cf038","repo":"chenhg5/cc-connect","slug":"no-openai-api-key-found","errorCode":null,"errorMessage":"no OPENAI_API_KEY found","messagePattern":"no OPENAI_API_KEY found","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/cc-connect/provider.go","lineNumber":417,"sourceCode":"\t}\n\treturn p, nil\n}\n\nfunc convertCodexProvider(p config.ProviderConfig, sc map[string]any) (config.ProviderConfig, error) {\n\t// API key from auth.OPENAI_API_KEY\n\tif auth, ok := sc[\"auth\"].(map[string]any); ok {\n\t\tif key, ok := auth[\"OPENAI_API_KEY\"].(string); ok && key != \"\" {\n\t\t\tp.APIKey = key\n\t\t}\n\t}\n\n\t// base_url and model from config TOML string\n\tif cfgStr, ok := sc[\"config\"].(string); ok && cfgStr != \"\" {\n\t\tp.BaseURL, p.Model = parseCodexConfigTOML(cfgStr)\n\t}\n\n\tif p.APIKey == \"\" {\n\t\treturn p, fmt.Errorf(\"no OPENAI_API_KEY found\")\n\t}\n\treturn p, nil\n}\n\n// parseCodexConfigTOML extracts base_url and model from a Codex config.toml string.\n// It handles both flat `base_url = \"...\"` and upstream-style `[model_providers.X]` sections.\nfunc parseCodexConfigTOML(cfgStr string) (baseURL, model string) {\n\tfor _, line := range strings.Split(cfgStr, \"\\n\") {\n\t\tline = strings.TrimSpace(line)\n\t\tif k, v, ok := parseTOMLKV(line); ok {\n\t\t\tswitch k {\n\t\t\tcase \"base_url\":\n\t\t\t\tif baseURL == \"\" {\n\t\t\t\t\tbaseURL = v\n\t\t\t\t}\n\t\t\tcase \"model\":\n\t\t\t\tif model == \"\" {\n\t\t\t\t\tmodel = v","sourceCodeStart":399,"sourceCodeEnd":435,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/cmd/cc-connect/provider.go#L399-L435","documentation":"convertCodexProvider builds a Codex provider entry from cc-switch data. After applying the config TOML (base_url, model), it requires an API key; if p.APIKey is still empty it refuses to return a usable provider and returns this error. It exists so a Codex provider without credentials is never silently used.","triggerScenarios":"Calling convertCCSwitchProvider/convertCodexProvider with a provider record whose api key field (OPENAI_API_KEY / apiKey in the cc-switch DB or settings JSON) is missing or empty.","commonSituations":"User imported a provider into cc-switch but never filled in OPENAI_API_KEY; key stored under an unexpected JSON key so parsing misses it; provider uses only env-var auth (e.g. ChatGPT login) with no explicit key.","solutions":["Open the provider entry in cc-switch (or its settings JSON) and set the OpenAI API key field.","Export OPENAI_API_KEY in the environment cc-connect runs under if the provider is meant to inherit it.","Re-import the provider from a complete config.toml that includes the key, then retry."],"exampleFix":"// before (provider settings in cc-switch)\n{ \"name\": \"my-provider\", \"config\": \"model_provider = ...\" }\n// after\n{ \"name\": \"my-provider\", \"apiKey\": \"sk-...\", \"config\": \"model_provider = ...\" }","handlingStrategy":"validation","validationCode":"if apiKey, _ := prov[\"apiKey\"].(string); strings.TrimSpace(apiKey) == \"\" {\n    return fmt.Errorf(\"provider %q has no OPENAI_API_KEY; set it in cc-switch before use\", prov[\"name\"])\n}","typeGuard":"apiKey, ok := sc[\"apiKey\"].(string); if !ok || strings.TrimSpace(apiKey) == \"\" { /* treat as unconfigured */ }","tryCatchPattern":"p, err := convertCCSwitchProvider(rec)\nif err != nil {\n    if strings.Contains(err.Error(), \"no OPENAI_API_KEY\") {\n        slog.Warn(\"skipping provider without API key\", \"provider\", rec.Name)\n        return\n    }\n    return err\n}","preventionTips":["Always fill the API key when creating a provider entry in cc-switch.","Validate provider records at import time, not at use time.","Keep keys in environment or secret store rather than omitting them."],"tags":["go","config","api-key","codex"],"backgroundTag":"missing-api-key","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}