golang/go · error
%s:%d: %w
Error message
%s:%d: %w
What it means
The lineErr closure in Engine.Run wraps any error that is not already a *CommandError with the script's filename and line number, giving every script failure a precise location. It fires for errors not tied to a single command's CommandError — script-reader I/O failures, context cancellation, end-of-section log-flush failures, or a custom Cmd that returns a bare error.
Source
Thrown at src/cmd/internal/script/engine.go:193
_, err = fmt.Fprintf(log, " (%.3fs)\n", time.Since(sectionStart).Seconds())
if err == nil && (!ok || !e.Quiet) {
err = s.flushLog(log)
} else {
s.log.Reset()
}
}
sectionStart = time.Time{}
return err
}
var lineno int
lineErr := func(err error) error {
if _, ok := errors.AsType[*CommandError](err); ok {
return err
}
return fmt.Errorf("%s:%d: %w", file, lineno, err)
}
// In case of failure or panic, flush any pending logs for the section.
defer func() {
if sErr := endSection(false); sErr != nil && err == nil {
err = lineErr(sErr)
}
}()
for {
if err := s.ctx.Err(); err != nil {
// This error wasn't produced by any particular command,
// so don't wrap it in a CommandError.
return lineErr(err)
}
line, err := script.ReadString('\n')
if err == io.EOF {View on GitHub (pinned to b6b368adc5)
Solutions
- Read the wrapped error (the %w portion) for the actual root cause and address that.
- If the cause is context cancellation, find the hang or increase the test timeout via testing.T.Deadline/-timeout.
- If authoring a custom Cmd, wrap failures with cmdError(cmd, err) so they are not double-wrapped and keep their CommandError identity.
- If the log writer failed, check the io.Writer passed to Run for faults (closed pipe, full buffer).
Example fix
// before (custom Cmd returns a bare error)
func(s *script.State, args ...string) (script.WaitFunc, error) {
return nil, errors.New("setup failed")
}
// after
func(s *script.State, args ...string) (script.WaitFunc, error) {
return nil, cmdError(cmd, errors.New("setup failed"))
} Defensive patterns
Strategy: try-catch
Try / catch
// When authoring a custom Cmd, wrap errors so they keep CommandError identity
// and are not re-wrapped by lineErr with just a file:line prefix.
runErr := impl.Run(s, cmd.args...)
if runErr != nil {
return cmdError(cmd, runErr) // preserves CommandError, lineErr leaves it alone
}
return nil Prevention
- Always wrap custom-command errors with cmdError(cmd, err).
- Set realistic test -timeout values to avoid context-cancellation wrappers masking a hang.
- When a file:line error appears, read the inner %w error first — it is the root cause.
When it happens
Trigger: s.ctx.Err() is non-nil (test cancelled/timed out) at engine.go:204; script.ReadString returns an I/O error; endSection fails while flushing logs; or a custom Cmd implementation returns errors.New(...) directly instead of wrapping via cmdError, so lineErr adds the file:line prefix.
Common situations: Test timeout cancelling the script context; a custom command returning a plain error; a log writer (io.Writer) failing; reaching this when debugging which script line caused a panic.
Related errors
- evaluating condition %q: %w
- unrecognized GOOS %q
- unrecognized GOARCH %q
- unrecognized compiler %q
- unknown condition prefix %q; known: %v
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/b516c2d8cfc89c3b.
Report an issue: GitHub.