golangci/golangci-lint · error
write file %s: %w
Error message
write file %s: %w
What it means
After regenerating plugins.go source, updatePluginsFile writes it back with os.WriteFile preserving the original file mode captured by the earlier Stat. If the write fails (permissions, read-only filesystem, disk full), the error wraps the cause as 'write file <path>: ...'.
Source
Thrown at pkg/commands/internal/imports.go:39
func (b Builder) updatePluginsFile() error {
importsDest := filepath.Join(b.repo, "cmd", "golangci-lint", "plugins.go")
info, err := os.Stat(importsDest)
if err != nil {
return fmt.Errorf("file %s not found: %w", importsDest, err)
}
source, err := generateImports(b.cfg)
if err != nil {
return fmt.Errorf("generate imports: %w", err)
}
b.log.Infof("generated imports info %s:\n%s\n", importsDest, source)
err = os.WriteFile(filepath.Clean(importsDest), source, info.Mode())
if err != nil {
return fmt.Errorf("write file %s: %w", importsDest, err)
}
return nil
}
func generateImports(cfg *Configuration) ([]byte, error) {
impTmpl, err := template.New("plugins.go").Parse(importsTemplate)
if err != nil {
return nil, fmt.Errorf("parse template: %w", err)
}
var imps []string
for _, plugin := range cfg.Plugins {
imps = append(imps, plugin.Import)
}
buf := &bytes.Buffer{}
View on GitHub (pinned to ed7a235d2d)
Solutions
- Make cmd/golangci-lint/plugins.go writable (chmod u+w or chown to the build user)
- Run the build outside read-only mounts or copy the repo to a writable location first
- Fix container UID/ownership so the build user can write the checkout
- Check disk space and that cmd/golangci-lint/ still exists
Example fix
// before $ golangci-lint custom # fails: write file ...: permission denied // after $ chmod u+w cmd/golangci-lint/plugins.go && golangci-lint custom
Defensive patterns
Strategy: validation
Validate before calling
p := filepath.Join(repo, "cmd", "golangci-lint", "plugins.go")
if info, err := os.Stat(p); err == nil && info.Mode().Perm()&0o200 == 0 {
os.Chmod(p, info.Mode()|0o200)
} Try / catch
err := builder.Build(ctx)
if err != nil && strings.Contains(err.Error(), "write file "+importsDest) {
var pe *fs.PathError
if errors.As(err, &pe) && errors.Is(pe.Err, os.ErrPermission) {
os.Chmod(importsDest, 0o644) // fix and retry
}
} Prevention
- Run builds on a writable checkout, not read-only mounts
- Chown/chmod the repo to the build user in CI containers
- Check disk space before long builds
- Never make generated files immutable (chattr +i)
When it happens
Trigger: os.WriteFile(importsDest) fails during Build — typically EACCES on cmd/golangci-lint/plugins.go, a read-only checkout, or the directory removed between Stat and Write.
Common situations: Building inside a container with a read-only mounted repo; file owned by root or another UID; disk full; generated file made immutable.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- create destination directory: %w
- failed to remove dir %s: %w
- create temporary directory: %w
- open source file: %w
- create destination file: %w
AI-assisted analysis of golangci/golangci-lint@ed7a235d2d (2026-09-02).
Data as JSON: /api/errors/60cd58d1b16933c6.
Report an issue: GitHub.