twpayne/chezmoi · error
%d: invalid format-indent-width
Error message
%d: invalid format-indent-width
What it means
chezmoi's template engine accepts a `format-indent-width` template directive that controls the indentation string used when re-formatting template output (e.g. JSON). The directive's value is parsed with strconv.Atoi and must be a non-negative integer; if the parsed number is negative, parseAndRemoveDirectives returns this error and template parsing fails. It is thrown to reject nonsensical indentation values at parse time rather than producing misformatted output.
Source
Thrown at internal/chezmoi/template.go:176
case "utf-16-be":
o.Encoding = unicode.UTF16(unicode.BigEndian, unicode.IgnoreBOM)
case "utf-16-be-bom":
o.Encoding = unicode.UTF16(unicode.BigEndian, unicode.UseBOM)
case "utf-16-le":
o.Encoding = unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM)
case "utf-16-le-bom":
o.Encoding = unicode.UTF16(unicode.LittleEndian, unicode.UseBOM)
default:
return nil, fmt.Errorf("%s: unknown encoding", value)
}
case "format-indent":
o.FormatIndent = value
case "format-indent-width":
switch width, err := strconv.Atoi(value); {
case err != nil:
return nil, err
case width < 0:
return nil, fmt.Errorf("%d: invalid format-indent-width", width)
default:
o.FormatIndent = strings.Repeat(" ", width)
}
case "left-delimiter":
o.LeftDelimiter = value
case "line-ending", "line-endings":
switch string(keyValuePairMatch[2]) {
case "crlf":
o.LineEnding = "\r\n"
case "lf":
o.LineEnding = "\n"
case "native":
o.LineEnding = nativeLineEnding
default:
o.LineEnding = value
}
case "right-delimiter":
o.RightDelimiter = valueView on GitHub (pinned to f901167e46)
Solutions
- Change the directive value to a non-negative integer, e.g. format-indent-width=2
- Check the template/config source for an accidental leading minus sign or a negative default leaking in
- If the value comes from code, clamp or validate it before building the option string
- If indentation should be disabled, use format-indent=false or a different directive instead of a negative width
Example fix
// before
options = append(options, "format-indent-width=-1")
// after
if width >= 0 {
options = append(options, fmt.Sprintf("format-indent-width=%d", width))
} Defensive patterns
Strategy: validation
Validate before calling
func validIndentWidth(v string) bool {
n, err := strconv.Atoi(v)
return err == nil && n >= 0
}
// only add "format-indent-width=N" when validIndentWidth(N-string) Try / catch
tpl, err := chezmoi.ParseTemplate(name, data, options)
if err != nil {
var nf *strconv.NumError
if strings.Contains(err.Error(), "invalid format-indent-width") || errors.As(err, &nf) {
// fall back to default options without the directive
}
return err
} Prevention
- Validate integer option values (>= 0) before adding them to template options
- Use named constants/enums for indentation instead of raw ints that may hold negative sentinels
- Add a unit test that parses every generated directive combination
- Prefer format-indent-width=0 over negative values when indentation should collapse
When it happens
Trigger: Calling chezmoi.ParseTemplate (or executing a template via parseAndRemoveDirectives) with a directive `format-indent-width` whose value parses to a negative integer, e.g. `{{ template "x" format-indent-width=-1 }}`-style option parsing where value is "-1", "-4", etc.
Common situations: Users hand-editing .chezmoitemplates or config template options and typo a minus sign; programmatically generating template options from config where a default of -1 means 'unset' and is passed through; copy-pasting examples that use negative sentinel values.
Related errors
AI-assisted analysis of twpayne/chezmoi@f901167e46 (2026-09-01).
Data as JSON: /api/errors/b2ebbdf4fb3ae33e.
Report an issue: GitHub.