{"record":{"id":"e64f6cff1245ffb2","repo":"grpc/grpc-go","slug":"xds-error-normalizing-json-bootstrap-configuratio","errorCode":null,"errorMessage":"xds: error normalizing JSON bootstrap configuration: %v","messagePattern":"xds: error normalizing JSON bootstrap configuration: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/xds/bootstrap/bootstrap.go","lineNumber":694,"sourceCode":"\n\tif fContent != \"\" {\n\t\tif logger.V(2) {\n\t\t\tlogger.Infof(\"Using bootstrap contents from GRPC_XDS_BOOTSTRAP_CONFIG environment variable\")\n\t\t}\n\t\treturn NewConfigFromContents([]byte(fContent))\n\t}\n\n\treturn nil, nil\n}\n\n// NewConfigFromContents creates a new bootstrap configuration from the provided\n// contents.\nfunc NewConfigFromContents(data []byte) (*Config, error) {\n\t// Normalize the input configuration.\n\tbuf := bytes.Buffer{}\n\terr := json.Indent(&buf, data, \"\", \"\")\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"xds: error normalizing JSON bootstrap configuration: %v\", err)\n\t}\n\tdata = bytes.TrimSpace(buf.Bytes())\n\n\tconfig := &Config{}\n\tif err := config.UnmarshalJSON(data); err != nil {\n\t\treturn nil, err\n\t}\n\treturn config, nil\n}\n\n// ConfigOptionsForTesting specifies options for creating a new bootstrap\n// configuration for testing purposes.\n//\n// # Testing-Only\ntype ConfigOptionsForTesting struct {\n\t// Servers is the top-level xDS server configuration. It contains a list of\n\t// server configurations.\n\tServers json.RawMessage","sourceCodeStart":676,"sourceCodeEnd":712,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/internal/xds/bootstrap/bootstrap.go#L676-L712","documentation":"Returned by NewConfigFromContents when json.Indent fails on the bootstrap contents, meaning the content is not syntactically valid JSON at all (this runs before any structural unmarshalling).","triggerScenarios":"Triggered at bootstrap.go:694 when json.Indent(&buf, data, \"\", \"\") errors on the raw bootstrap content (file via GRPC_XDS_BOOTSTRAP or inline via GRPC_XDS_BOOTSTRAP_CONFIG).","commonSituations":"Trailing comma; unquoted keys; JSON comments (// or /* */); single quotes; YAML mistakenly used; a UTF-8 BOM or stray control characters; truncated file.","solutions":["Validate the file with a strict JSON parser: jq . bootstrap.json or python -m json.tool bootstrap.json.","Remove JSON comments and trailing commas.","If you need a config format with comments, generate the JSON from it at deploy time instead of embedding comments.","Re-export the file as UTF-8 without BOM."],"exampleFix":"// before (trailing comma, comments)\n{\n  // xDS servers\n  \"xds_servers\": [...],  // <-- trailing comma\n}\n\n// after (strict JSON)\n{\n  \"xds_servers\": [...]\n}","handlingStrategy":"validation","validationCode":"// Strict JSON syntax check on the bootstrap content.\nfunc validateJSONSyntax(data []byte) error {\n    var v any\n    dec := json.NewDecoder(bytes.NewReader(data))\n    dec.DisallowUnknownFields() // optional\n    if err := dec.Decode(&v); err != nil {\n        return fmt.Errorf(\"bootstrap JSON syntax: %w\", err)\n    }\n    if dec.More() {\n        return fmt.Errorf(\"bootstrap has trailing content\")\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if _, err := bootstrap.NewConfigFromContents(data); err != nil {\n    if strings.Contains(err.Error(), \"normalizing JSON\") {\n        // run the file through jq to find the syntax error.\n    }\n}","preventionTips":["Never put comments or trailing commas in the bootstrap file.","Generate JSON from a templating system rather than hand-writing.","Re-export as UTF-8 without BOM."],"tags":["grpc","xds","bootstrap","json","config","go"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}