{"record":{"id":"dfb0b64463178e0b","repo":"sipeed/picoclaw","slug":"failed-to-load-config-v-dfb0b6","errorCode":null,"errorMessage":"Failed to load config: %v","messagePattern":"Failed to load config: (.+?)","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"web/backend/api/models.go","lineNumber":244,"sourceCode":"\t\treturn false\n\t}\n\n\tchanged := false\n\tfor _, model := range cfg.ModelList {\n\t\tif normalizeStoredModelConfig(model) {\n\t\t\tchanged = true\n\t\t}\n\t}\n\treturn changed\n}\n\n// handleListModels returns all model_list entries with masked API keys.\n//\n//\tGET /api/models\nfunc (h *Handler) handleListModels(w http.ResponseWriter, r *http.Request) {\n\tcfg, err := config.LoadConfig(h.configPath)\n\tif err != nil {\n\t\thttp.Error(w, fmt.Sprintf(\"Failed to load config: %v\", err), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\t// Normalize legacy provider/model storage in memory so GET can round-trip\n\t// through the current API shape without mutating the on-disk config.\n\tnormalizeStoredModelProviders(cfg)\n\n\tdefaultModel := cfg.Agents.Defaults.GetModelName()\n\tmodelStatuses := make([]modelConfigurationSummary, len(cfg.ModelList))\n\n\tvar wg sync.WaitGroup\n\twg.Add(len(cfg.ModelList))\n\tfor i, m := range cfg.ModelList {\n\t\tgo func(i int, m *config.ModelConfig) {\n\t\t\tdefer wg.Done()\n\t\t\tmodelStatuses[i] = modelConfigurationStatus(m)\n\t\t}(i, m)\n\t}","sourceCodeStart":226,"sourceCodeEnd":262,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/web/backend/api/models.go#L226-L262","documentation":"HTTP 500 returned by GET /api/models (handleListModels) when config.LoadConfig(h.configPath) fails. A missing config file is tolerated (defaults are returned), so this only fires when the file exists but cannot be read or parsed: permission denied, path is a directory, malformed JSON, or a failed legacy v0-to-v1 migration. The backend logs a 'Malformed config file' diagnostic with byte offset from wrapJSONError before responding.","triggerScenarios":"GET /api/models when config.json on the server has a JSON syntax error (trailing comma, unescaped quote), is chmod 000 or owned by root while the backend runs as a normal user, has been replaced by a directory, or contains a legacy v0 payload that fails validateLegacyConfigDiagnostics/migrateV0ToV1.","commonSituations":"Hand-editing config.json and introducing a typo; running the service under a different user than the one that created the config; an app upgrade that changes schema version while the old file cannot migrate; another tool (sync agent, editor backup swap) corrupting or truncating the file mid-write.","solutions":["Check the backend log for the 'Malformed config file' entry which names the offending byte/position in config.json","Validate the file: jq . \"$(config path)\" or a JSON linter, and fix the reported syntax error","Fix permissions: chmod 600 config.json and chown it to the user running the backend process","If migration fails (V0→V1 error in log), back up config.json, delete it, and let the app regenerate defaults, then re-add models"],"exampleFix":"# before: config.json left broken after hand edit\n{\n  \"model_list\": [ {\"model_name\": \"gpt\",}, ],\n}\n\n# after: valid JSON, no trailing commas\n{\n  \"model_list\": [\n    { \"model_name\": \"gpt\", \"model\": \"openai/gpt-4o\", \"provider\": \"openai\" }\n  ]\n}","handlingStrategy":"try-catch","validationCode":"// local pre-flight when you control the host: confirm the config parses before the request\n// jq -e . \"$CONFIG_PATH\" >/dev/null || echo 'config.json is invalid — fix before using the API'","typeGuard":null,"tryCatchPattern":"const res = await fetch('/api/models');\nif (!res.ok) {\n  const detail = await res.text(); // contains the LoadConfig cause\n  throw new Error(`GET /api/models failed (${res.status}): ${detail}`);\n}\nconst data = await res.json();","preventionTips":["Never hand-edit config.json while the backend is running; use the API endpoints","Validate config.json with a JSON linter after any manual change","Keep the backend process and config file under the same OS user","Back up config.json before app upgrades that change schema versions"],"tags":["go","http","config","json","internal-server-error"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}