{"record":{"id":"507deae9cf2b3f86","repo":"jesseduffield/lazygit","slug":"all-gui-spinner-frames-entries-must-have-the-same","errorCode":null,"errorMessage":"All gui.spinner.frames entries must have the same width.","messagePattern":"All gui\\.spinner\\.frames entries must have the same width\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/config/user_config_validation.go","lineNumber":108,"sourceCode":"\t// conflict or popping a stash), so they must always be present; otherwise\n\t// that code would focus a hidden panel.\n\tfor _, required := range []string{\"files\", \"branches\", \"commits\"} {\n\t\tif !seen[required] {\n\t\t\treturn fmt.Errorf(\"gui.sidePanels: '%s' must be included; it can't be hidden.\", required)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc validateSpinner(spinner SpinnerConfig) error {\n\tif len(spinner.Frames) == 0 {\n\t\treturn errors.New(\"gui.spinner.frames must not be empty.\")\n\t}\n\tfirstWidth := utils.StringWidth(spinner.Frames[0])\n\tif lo.SomeBy(spinner.Frames, func(frame string) bool {\n\t\treturn utils.StringWidth(frame) != firstWidth\n\t}) {\n\t\treturn errors.New(\"All gui.spinner.frames entries must have the same width.\")\n\t}\n\treturn nil\n}\n\nfunc validateDiffRenderers(diffRenderers []DiffRendererConfig) error {\n\tfor _, diffRenderer := range diffRenderers {\n\t\tswitch diffRenderer.Type {\n\t\tcase \"stdinFilter\", \"\":\n\t\t\tif diffRenderer.Command == \"\" {\n\t\t\t\treturn errors.New(\"git.diffRenderers: 'command' must be specified for diff renderer type 'stdinFilter'.\")\n\t\t\t}\n\t\t\tif len(diffRenderer.Args) > 0 {\n\t\t\t\treturn errors.New(\"git.diffRenderers: 'args' cannot be used with diff renderer type 'stdinFilter'.\")\n\t\t\t}\n\t\tcase \"extDiff\":\n\t\t\tif len(diffRenderer.Args) > 0 {\n\t\t\t\treturn errors.New(\"git.diffRenderers: 'args' cannot be used with diff renderer type 'extDiff'.\")\n\t\t\t}","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/jesseduffield/lazygit/blob/c477a2959b229fbf3284be0d4d2904ab61ec3c94/pkg/config/user_config_validation.go#L90-L126","documentation":"Validation error from validateSpinner (user_config_validation.go:108). All gui.spinner.frames entries must have the same display width (measured with utils.StringWidth, unicode-aware); mixed-width frames make the spinner jitter and break layout, so config load fails. The first frame's width is the reference.","triggerScenarios":"Mixing frames of differing widths, including double-width CJK/emoji frames with narrow ASCII ones, or combining '⠋' with '-'. utils.StringWidth accounts for East Asian wide characters, so width is visual columns, not rune count.","commonSituations":"Copy-pasting a spinner from a font/terminal that renders differently; mixing emoji (often width 2) with braille frames (width 1); hand-crafted frames with a trailing space in only some entries.","solutions":["Inspect each frame for stray spaces or hidden characters (e.g. with a hex view)","Use frames from a single character set — all braille, all ASCII, or all emoji","Pad narrower frames with spaces to match the widest frame's column width","Validate widths yourself with a unicode-width aware function before saving"],"exampleFix":"# before\ngui:\n  spinner:\n    frames: ['⠋', '🌧️']  # width 1 vs width 2\n\n# after\ngui:\n  spinner:\n    frames: ['⠋', '⠙', '⠹', '⠸']  # uniform width 1","handlingStrategy":"type-guard","validationCode":"import \"github.com/mattn/go-runewidth\"\n\nfunc uniformSpinnerWidth(frames []string) bool {\n    if len(frames) == 0 {\n        return false\n    }\n    w := runewidth.StringWidth(frames[0])\n    for _, f := range frames[1:] {\n        if runewidth.StringWidth(f) != w {\n            return false\n        }\n    }\n    return true\n}","typeGuard":"func isUniformWidthFrameSet(frames []string) bool {\n    return uniformSpinnerWidth(frames)\n}","tryCatchPattern":null,"preventionTips":["Pick frames from one character set (all braille or all ASCII)","Beware emoji and CJK runes — they are width 2 in terminals","Check for trailing spaces in individual frames"],"tags":["config","unicode","validation","spinner"],"backgroundTag":null,"analyzedSha":"c477a2959b229fbf3284be0d4d2904ab61ec3c94","analyzedAt":"2026-08-15T08:34:32.451Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}