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

  1. Read the wrapped inner error - it names the specific segment/template/flag that render.Config rejected.
  2. 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.
  3. If the error came from data.ApplyFlags, correct the dataJSON contents (valid pwd path, valid status) or pass '' to skip recorded data.
  4. 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

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


AI-assisted analysis of JanDeDobbeleer/oh-my-posh@0976794618 (2026-08-31). Data as JSON: /api/errors/6cdd9134bf3633ec. Report an issue: GitHub.