golangci/golangci-lint · error
printing %s: %w
Error message
printing %s: %w
What it means
writeNewFile serializes the transformed AST back to text with printer.Fprint. The 'printing %s: %w' wrap means the go/printer failed to emit the AST. This is rare — go/printer only errors on internal problems like an AST node with invalid positions or malformed comments — and typically points to a bug in the AST mutation done by processFile/processStructFields.
Source
Thrown at pkg/commands/internal/migrate/cloner/cloner.go:176
if key == ",squash" {
return wrapStructTag(`yaml:",inline"`)
}
return wrapStructTag(fmt.Sprintf(`yaml:"%[1]s,omitempty" toml:"%[1]s,multiline,omitempty"`, key))
}
func wrapStructTag(s string) string {
return "`" + s + "`"
}
func writeNewFile(fset *token.FileSet, file *ast.File, srcPath, dstDir string) error {
var buf bytes.Buffer
buf.WriteString("// Code generated by pkg/commands/internal/migrate/cloner/cloner.go. DO NOT EDIT.\n\n")
err := printer.Fprint(&buf, fset, file)
if err != nil {
return fmt.Errorf("printing %s: %w", srcPath, err)
}
dstPath := filepath.Join(dstDir, filepath.Base(srcPath))
_ = os.MkdirAll(filepath.Dir(dstPath), os.ModePerm)
formatted, err := imports.Process(dstPath, buf.Bytes(), nil)
if err != nil {
return fmt.Errorf("formatting %s: %w", dstPath, err)
}
//nolint:gosec,mnd // The permission is right.
err = os.WriteFile(dstPath, formatted, 0o644)
if err != nil {
return fmt.Errorf("writing file %s: %w", dstPath, err)
}
return nilView on GitHub (pinned to ed7a235d2d)
Solutions
- Look at the wrapped printer error to identify which node/position is invalid
- Verify any hand-constructed ast nodes (e.g. StarExpr in convertType) reuse positions from the original expression rather than token.NoPos where possible
- Run gofmt on the source file to rule out unusual formatting/comment edge cases
- Simplify the AST mutation, or re-derive nodes with ast.NewIdent / copied positions, then re-run the cloner
Example fix
// before
return &ast.StarExpr{X: ident}
// after (preserve source position so the printer can emit valid output)
return &ast.StarExpr{Star: ident.Pos(), X: ident} Defensive patterns
Strategy: try-catch
Validate before calling
// pre-check: print the mutated AST to a buffer and gofmt-validate before writing
var pre bytes.Buffer
if err := printer.Fprint(&pre, fset, file); err != nil {
return fmt.Errorf("printing %s: %w", srcPath, err)
}
if _, err := format.Source(pre.Bytes()); err != nil {
return fmt.Errorf("printed AST invalid for %s: %w", srcPath, err)
} Try / catch
if err := writeNewFile(fset, file, srcPath, dstDir); err != nil {
if strings.Contains(err.Error(), "printing ") {
log.Printf("printer failed for %s: %v — inspect AST mutations", srcPath, err)
}
return err
} Prevention
- When building AST nodes manually, copy positions from the original nodes
- Avoid token.NoPos on synthesized nodes where possible
- Test transformations on files containing comments and multi-line declarations
- Keep AST mutation logic (processFile) minimal and reviewed
When it happens
Trigger: writeNewFile is called (from the processPackage walk callback) after processFile mutated the AST, and printer.Fprint returns an error, usually because hand-constructed or mutated AST nodes carry inconsistent position info (e.g. a StarExpr wrapping an ident whose Pos is invalid after field manipulation).
Common situations: Extending the cloner's AST transformations (convertType, processStructFields) with manually built nodes lacking valid positions; corrupted comment positions in the source file can also trip the printer.
Related errors
AI-assisted analysis of golangci/golangci-lint@ed7a235d2d (2026-09-02).
Data as JSON: /api/errors/1d45e0913aa0a9ce.
Report an issue: GitHub.