JanDeDobbeleer/oh-my-posh · error
failed to render config: %w
Error message
failed to render config: %w
What it means
Returned by renderSVG (src/wasm/main.go:163) when render.Config fails to build a rendering engine from the already-parsed config. render.Config validates the config and applies flags (here via the mandatory applyData closure that sets flags.DataOnly), so any error it reports - invalid template/function setup, flag application failure, bad segment config surfaced during engine construction - is wrapped as "failed to render config: %w". Unlike the parse errors, this fires after the config text parsed successfully.
Source
Thrown at src/wasm/main.go:163
}
// terminal.CaptureRuns must be set before render.Config's own
// eng.Primary() call runs - render.Config's doc comment explains why
// that line can't live inside render.Config itself, and every caller
// (the CLI image command, this one) sets it at its own call site instead.
terminal.CaptureRuns = true
columns := jsInt(optionsGet(options, "columns"), 120)
// resetTemplateCache is true, unlike the CLI's single-shot image/data
// commands: this wasm instance stays alive across many calls to
// render() - once per keystroke in a studio preview, say - so each call
// must start the template cache fresh, or one render's Var/Maps would
// leak into the next. See render.Config's own doc comment for the exact
// same reasoning applied to recordThemeSanitized's per-theme loop.
eng, err := render.Config(cfg, columns, true, applyData)
if err != nil {
return "", fmt.Errorf("failed to render config: %w", err)
}
metrics := render.FontMetrics{
CellWidth: jsFloat(optionsGet(options, "cellWidth")),
LineHeight: jsFloat(optionsGet(options, "lineHeight")),
FillAscent: jsFloat(optionsGet(options, "fillAscent")),
FillDescent: jsFloat(optionsGet(options, "fillDescent")),
}
opts := render.SVGOptions(jsString(optionsGet(options, "fontFamily")), columns, metrics)
// A caller-supplied canvas background (the website's studio, switching between its own
// dark/light color mode) only ever fills in for a theme that leaves its own terminal
// background unset - withDefaults (svg.go) always prefers a real opts.TerminalBackground
// over CanvasBackground when the theme sets one, so this can't paint over how the theme
// would actually look in a real terminal. Same convention as the CLI's own
// --background-color flag (cli/config_export_svg.go's exportSVG).
if backgroundColor := jsString(optionsGet(options, "backgroundColor")); backgroundColor != "" {View on GitHub (pinned to 0976794618)
Solutions
- Read the wrapped inner error - it names the specific segment/template/flag that render.Config rejected.
- Fix the offending template expression in the config text; validate templates with the oh-my-posh debug/CLI render before loading them in the browser.
- If the error came from data.ApplyFlags, correct the dataJSON contents (valid pwd path, valid status) or pass '' to skip recorded data.
- Reduce the config to a minimal single-segment version and bisect until the failing segment is isolated.
Example fix
// before: bad template
{ "type": "path", "template": "{{ .UnknownField | bogusFunc }}" }
// after: valid template
{ "type": "path", "template": "{{ .Path }}" } Defensive patterns
Strategy: try-catch
Validate before calling
// validate config and templates with the CLI before loading into wasm:
// oh-my-posh config render --config ./theme.omp.json
function validateBeforeRender(configText) {
if (typeof configText !== 'string' || configText.trim() === '') return true; // empty -> default config is safe
return true; // structural validation happens via render.Config; catch at call site
} Try / catch
try {
const svg = omp.render(cfg, 'json', dataJSON, options);
} catch (e) {
if (String(e).includes('failed to render config')) {
// the wrapped message names the failing segment/template/flag
console.error('Config failed to render:', e.message);
showEditorErrorAt(e.message); // surface the inner error to the user
} else { throw e; }
} Prevention
- Test themes with `oh-my-posh config render` or `oh-my-posh debug` locally before loading them in the browser.
- Keep template expressions simple and validate variables exist with `default` filters.
- If passing dataJSON, ensure ApplyFlags-compatible values (valid pwd path string, valid status).
- Bisect multi-segment themes down to the failing segment when the inner error is unclear.
When it happens
Trigger: Calling wasm render(configText, format, dataJSON, options) where configText parses but render.Config rejects it: a malformed template expression in a segment, a data blob whose ApplyFlags fails (invalid pwd/status data passed via dataJSON), or an invalid column/flag combination. Config text that parses cleanly under format but references unsupported options during engine build.
Common situations: Editing a theme in the web studio and introducing a bad template like {{ .Segment.Data }} on a nil map; supplying a dataJSON whose pwd is not a valid path string; referencing a template function with wrong arity that fails at engine construction; rendering a theme that requires env probing while DataOnly forces recorded data only.
Related errors
- failed to parse data: %w
- panic(err)
- invalid export format
- unclosed section:
- key-value delimiter not found:
AI-assisted analysis of JanDeDobbeleer/oh-my-posh@0976794618 (2026-08-31).
Data as JSON: /api/errors/6cdd9134bf3633ec.
Report an issue: GitHub.