{"record":{"id":"79c13d6600ac76ce","repo":"charmbracelet/crush","slug":"invalid-json-in-config-file-s","errorCode":null,"errorMessage":"invalid JSON in config file %s","messagePattern":"invalid JSON in config file (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/config/load.go","lineNumber":69,"sourceCode":"\n\tcfg.setDefaults(workingDir, dataDir)\n\n\tstore := &ConfigStore{\n\t\tconfig:         cfg,\n\t\tworkingDir:     workingDir,\n\t\tglobalDataPath: GlobalConfigData(),\n\t\tworkspacePath:  filepath.Join(cfg.Options.DataDirectory, fmt.Sprintf(\"%s.json\", appName)),\n\t\tloadedPaths:    loadedPaths,\n\t}\n\n\tif debug {\n\t\tcfg.Options.Debug = true\n\t}\n\n\t// Load workspace config last so it has highest priority.\n\tif wsData, err := os.ReadFile(store.workspacePath); err == nil && len(wsData) > 0 {\n\t\tif !json.Valid(wsData) {\n\t\t\treturn nil, fmt.Errorf(\"invalid JSON in config file %s\", store.workspacePath)\n\t\t}\n\t\tmerged, mergeErr := loadFromBytes(append([][]byte{mustMarshalConfig(cfg)}, wsData))\n\t\tif mergeErr == nil {\n\t\t\t// Preserve defaults that setDefaults already applied.\n\t\t\tdataDir := cfg.Options.DataDirectory\n\t\t\t*cfg = *merged\n\t\t\tcfg.setDefaults(workingDir, dataDir)\n\t\t\tstore.config = cfg\n\t\t\tstore.loadedPaths = append(store.loadedPaths, store.workspacePath)\n\t\t}\n\t}\n\n\t// Validate hooks after all config merging is complete so workspace\n\t// hooks also get their matcher regexes compiled.\n\tif err := cfg.ValidateHooks(); err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid hook configuration: %w\", err)\n\t}\n","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/config/load.go#L51-L87","documentation":"Load() validates that the workspace config file (highest-priority crush.json) contains syntactically valid JSON before merging it. It fails fast with the file path so the user knows which file to fix, because a partial merge of malformed JSON would silently produce a broken config.","triggerScenarios":"os.ReadFile on store.workspacePath succeeds and returns bytes, but json.Valid(wsData) returns false — e.g. trailing commas, comments in JSON, truncated writes, or hand-edits that broke syntax.","commonSituations":"Users hand-editing ~/.config/crush/crush.json and leaving a syntax error; editors saving partial content; tools appending to the JSON producing invalid output; copy-pasted config containing comments or trailing commas.","solutions":["Open the file named in the error and fix the JSON syntax (validate with a JSON linter or `jq . file`)","Remove JSON-incompatible content such as // comments or trailing commas, or migrate the file to crushrc format","Restore the file from backup or delete it to start with defaults","Check for a crashed editor or interrupted write that truncated the file"],"exampleFix":"// before (crush.json)\n{\"providers\": {\"anthropic\": {\"api_key\": \"sk-...\",}},}\n// after\n{\"providers\": {\"anthropic\": {\"api_key\": \"sk-...\"}}}","handlingStrategy":"validation","validationCode":"data, err := os.ReadFile(configPath)\nif err != nil { return err }\nif !json.Valid(data) {\n    return fmt.Errorf(\"fix JSON syntax in %s: run `jq . %s` to locate the error\", configPath, configPath)\n}","typeGuard":null,"tryCatchPattern":"store, err := config.Load(ctx, opts)\nif err != nil {\n    var pathErr *os.PathError\n    if strings.Contains(err.Error(), \"invalid JSON in config file\") {\n        // surface the file path from err and prompt user to repair\n    }\n    return err\n}","preventionTips":["Validate crush.json with a JSON linter or `jq . file` after every hand edit","Keep configs in version control to diff/restore broken edits","Prefer the crushrc (Bash) format which tolerates comments over hand-written JSON","Use editors with JSON schema validation for config files"],"tags":["config","json","validation"],"backgroundTag":"invalid-json-in-config","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}