golangci/golangci-lint · error
can't create output for %s: %w
Error message
can't create output for %s: %w
What it means
Printer.Print wraps any error returned by createWriter for the text output path. createWriter fails when it cannot MkdirAll the parent directory or cannot os.OpenFile the report file (O_CREATE|O_TRUNC|O_WRONLY, mode 0644); relative paths are resolved against basePath first.
Source
Thrown at pkg/printers/printer.go:76
stdOut: logutils.StdOut,
stdErr: logutils.StdErr,
}, nil
}
// Print prints issues based on the formats defined.
//
//nolint:gocyclo,funlen // the complexity is related to the number of formats.
func (c *Printer) Print(issues []*result.Issue) error {
if c.cfg.IsEmpty() {
c.cfg.Text.Path = outputStdOut
}
var printers []issuePrinter
if c.cfg.Text.Path != "" {
w, closer, err := c.createWriter(&c.cfg.Text.SimpleFormat)
if err != nil {
return fmt.Errorf("can't create output for %s: %w", c.cfg.Text.Path, err)
}
defer closer()
printers = append(printers, NewText(c.log, w, &c.cfg.Text))
}
if c.cfg.JSON.Path != "" {
w, closer, err := c.createWriter(&c.cfg.JSON)
if err != nil {
return fmt.Errorf("can't create output for %s: %w", c.cfg.JSON.Path, err)
}
defer closer()
printers = append(printers, NewJSON(w, c.reportData))
}
View on GitHub (pinned to ed7a235d2d)
Solutions
- Check the wrapped os error: fix permissions (chmod/chown) or create the parent directory for the configured output path
- Point output.formats.text.path to a writable file (not a directory), or use 'stdout'/'stderr' to stream to the terminal
- In containers/CI, mount or set a writable output directory and pass an absolute path
- Verify basePath: relative paths are joined with basePath, so run from the expected working directory or use an absolute path
Example fix
// before (.golangci.yml)
output:
formats:
text:
path: reports/
// after
output:
formats:
text:
path: reports/lint.txt # must be a writable FILE path Defensive patterns
Strategy: validation
Validate before calling
p := filepath.Join(basePath, cfg.Output.Formats.Text.Path)
if p != "stdout" && p != "stderr" {
if err := os.MkdirAll(filepath.Dir(p), 0o755); err != nil {
return fmt.Errorf("text output dir not writable: %w", err)
}
if fi, err := os.Stat(p); err == nil && fi.IsDir() {
return fmt.Errorf("%s is a directory, expected a file", p)
}
f, err := os.OpenFile(p, os.O_CREATE|os.O_WRONLY, 0o644)
if err != nil {
return fmt.Errorf("text output not writable: %w", err)
}
f.Close()
} Try / catch
if err := p.Print(issues); err != nil {
var perr *fs.PathError
if errors.As(err, &perr) && strings.Contains(err.Error(), "can't create output") {
log.Printf("report path %s unwritable (%v); falling back to stdout", perr.Path, perr.Err)
}
} Prevention
- Always point output paths at files, never directories
- Use 'stdout'/'stderr' literals when a file is unnecessary
- Pre-create and permission-check report directories in CI before running golangci-lint
- Prefer absolute paths or run from a known working directory so basePath joining is predictable
When it happens
Trigger: output.formats.text.path set to a file path that cannot be created: parent directory missing/unwritable, path is an existing directory, read-only filesystem, or permission denied; createWriter returns the os error which is wrapped here.
Common situations: CI containers with read-only workspaces, output paths pointing into nonexistent mount points, path is a directory (e.g. 'out/' or 'reports'), running as non-root user without write perms, Windows-invalid path characters, SELinux/AppArmor denials.
Related errors
- can't write heap profile: %w
- the configuration contains invalid elements
- unsupported configuration format
- the configuration contains invalid elements
- parallel golangci-lint is running
AI-assisted analysis of golangci/golangci-lint@ed7a235d2d (2026-09-02).
Data as JSON: /api/errors/9408065b6b6c8e5a.
Report an issue: GitHub.