JanDeDobbeleer/oh-my-posh · error
unexpected data after top-level value
Error message
unexpected data after top-level value
What it means
ParseBytes decodes JSON/JSONC configs with json.Decoder.Decode, which by design reads only the FIRST top-level value. To catch what json.Unmarshal would reject, it then reads one more token and requires io.EOF; if any extra token follows the top-level JSON object, this error is raised (and ParseBytes ultimately returns ErrParse). It exists so stray trailing text is reported instead of silently ignored.
Source
Thrown at src/config/load.go:297
cfg.Format = YAML
parseErr = yaml.Unmarshal(data, &cfg)
case JSONC, JSON:
cfg.Format = JSON
str := text.StripJSONComments(string(data))
data = []byte(str)
decoder := json.NewDecoder(bytes.NewReader(data))
parseErr = decoder.Decode(&cfg)
// decoder.Decode only reads the first JSON value and, unlike
// json.Unmarshal, never checks what follows it - a stray character
// after the closing brace (a leftover paste, a misplaced comma) would
// otherwise be silently ignored rather than reported as the parse
// error it is.
if parseErr == nil {
if _, tokErr := decoder.Token(); tokErr != io.EOF {
parseErr = fmt.Errorf("unexpected data after top-level value")
}
}
case TOML, TML:
cfg.Format = TOML
parseErr = toml.Unmarshal(data, &cfg)
default:
log.Errorf("unsupported config file format: %s", cfg.Format)
return nil, ErrInvalidExtension
}
if parseErr != nil {
log.Errorf("failed to parse config: %v", parseErr)
return nil, ErrParse
}
populatePresence(&cfg, data)
return &cfg, nilView on GitHub (pinned to 0976794618)
Solutions
- Inspect the JSON text after the final closing brace of the top-level object and delete everything there
- If two JSON documents were concatenated, split them or merge them into one object
- Validate the file with a strict JSON parser (jq .) - it reports 'trailing characters' at the same spot
- Re-export or re-download the theme file if it was truncated/corrupted
Example fix
// before
{ "version": 3 } { "version": 2 }
// after
{ "version": 3 } Defensive patterns
Strategy: try-catch
Validate before calling
func strictJSON(data []byte) error {
return json.Unmarshal(data, &map[string]any{}) // Unmarshal rejects trailing data
}
// or: jq empty config.json Try / catch
cfg, err := config.ParseBytes(config.JSON, raw)
if err != nil {
if errors.Is(err, config.ErrParse) {
// locate trailing garbage: scan past the first balanced top-level object
}
return err
} Prevention
- Never concatenate JSON documents - merge objects instead
- Diff edited theme files against the original to spot leftover fragments
- Run jq (or a strict parser) over JSON configs in CI
- Beware of tools that append text after JSON output
When it happens
Trigger: Calling ParseBytes (or read/renderSVG which call it) with JSON bytes containing anything after the closing brace of the top-level object: a second concatenated object, a leftover fragment, a stray comma or character.
Common situations: Concatenating two theme JSON files by accident; a copy-paste leaving remnants of an old config after the final '}'; a template/script appending text after the JSON; editing tools leaving trailing garbage after a truncation.
Related errors
- failed to parse recorded theme %s: %w
- failed to parse env for theme %s: %w
- failed to parse segments for theme %s: %w
- failed to parse data file: %w
- failed to parse nerd fonts release
AI-assisted analysis of JanDeDobbeleer/oh-my-posh@0976794618 (2026-08-31).
Data as JSON: /api/errors/e5dda3c795b17e82.
Report an issue: GitHub.