{"record":{"id":"9327adf0e64d96dd","repo":"jaegertracing/jaeger","slug":"cannot-parse-ui-config-file-v-w","errorCode":null,"errorMessage":"cannot parse UI config file %v: %w","messagePattern":"cannot parse UI config file (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/jaeger/internal/extension/jaegerquery/internal/static_handler.go","lineNumber":224,"sourceCode":"}\n\nfunc loadUIConfig(uiConfig string) (*loadedConfig, error) {\n\tif uiConfig == \"\" {\n\t\treturn nil, nil\n\t}\n\tbytesConfig, err := os.ReadFile(filepath.Clean(uiConfig))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"cannot read UI config file %v: %w\", uiConfig, err)\n\t}\n\tvar r []byte\n\n\text := filepath.Ext(uiConfig)\n\tswitch strings.ToLower(ext) {\n\tcase \".json\":\n\t\tvar c map[string]any\n\n\t\tif err := json.Unmarshal(bytesConfig, &c); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"cannot parse UI config file %v: %w\", uiConfig, err)\n\t\t}\n\t\tr, _ = json.Marshal(c)\n\n\t\treturn &loadedConfig{\n\t\t\tregexp: configPattern,\n\t\t\tconfig: append([]byte(\"JAEGER_CONFIG = \"), append(r, byte(';'))...),\n\t\t}, nil\n\tcase \".js\":\n\t\tr = bytes.TrimSpace(bytesConfig)\n\t\tre := regexp.MustCompile(`function\\s+UIConfig(\\s)?\\(\\s?\\)(\\s)?{`)\n\t\tif !re.Match(r) {\n\t\t\treturn nil, fmt.Errorf(\"UI config file must define function UIConfig(): %v\", uiConfig)\n\t\t}\n\n\t\treturn &loadedConfig{\n\t\t\tregexp: configJsPattern,\n\t\t\tconfig: r,\n\t\t}, nil","sourceCodeStart":206,"sourceCodeEnd":242,"githubUrl":"https://github.com/jaegertracing/jaeger/blob/806f4447841ecdb60519f408b004a599d515f437/cmd/jaeger/internal/extension/jaegerquery/internal/static_handler.go#L206-L242","documentation":"The UI config file was read successfully but is not valid JSON: json.Unmarshal into map[string]any failed. Jaeger re-marshals the parsed map to produce the JAEGER_CONFIG blob injected into index.html, so the file must be strict JSON when it has a .json extension.","triggerScenarios":"loadUIConfig with a file whose extension is .json (case-insensitive) where json.Unmarshal(bytesConfig, &c) returns an error — malformed JSON, trailing commas, comments, duplicate keys of wrong type, or BOM/HTML content saved as .json.","commonSituations":"Hand-edited JSON with a trailing comma or single quotes; a config file copied from docs containing /* comments */; saving a .js UI config with a .json extension; editor adding a UTF-8 BOM.","solutions":["Validate the file with a JSON linter (jq . ui-config.json) and fix the syntax error reported by the wrapped error.","Remove comments, trailing commas, and BOM — strict JSON only.","If the file is actually JavaScript, rename it to .js so it takes the JS parsing branch instead.","Regenerate the config from your UI config tooling rather than hand-editing."],"exampleFix":"// before (ui-config.json)\n{ \"menu\": [ { \"label\": \"Docs\", \"url\": \"https://jaeger.dev\", }, ] }\n// after\n{ \"menu\": [ { \"label\": \"Docs\", \"url\": \"https://jaeger.dev\" } ] }","handlingStrategy":"validation","validationCode":"var probe map[string]any\nif err := json.NewDecoder(bytes.NewReader(bytesConfig)).Decode(&probe); err != nil {\n    return fmt.Errorf(\"ui config %s is not valid JSON: %w\", path, err)\n}","typeGuard":null,"tryCatchPattern":"if err := json.Unmarshal(data, &c); err != nil {\n    var syn *json.SyntaxError\n    if errors.As(err, &syn) {\n        log.Printf(\"JSON syntax at offset %d: %v\", syn.Offset, syn.Error())\n    }\n    return err\n}","preventionTips":["Run `jq empty file.json` in CI for every UI config.","Strip BOM and comments before shipping configs.","Keep .js configs out of files with a .json extension."],"tags":["json","config","parse-error","jaeger-query"],"backgroundTag":"json-parse-error","analyzedSha":"806f4447841ecdb60519f408b004a599d515f437","analyzedAt":"2026-09-01T02:39:22.140Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}