FiloSottile/age · error
%v
Error message
%v
What it means
fatalInteractf formats the underlying interaction error, writes it to the plugin's stderr, sets the plugin's broken flag so subsequent Wrap/Unwrap calls exit with an error, and returns the formatted error. The message text is simply the wrapped interaction protocol error, so the real cause is the format arguments (e.g. a malformed stanza or read failure).
Source
Thrown at plugin/plugin.go:580
s, err = readOkOrFail(p.sr)
if err != nil {
return false, p.fatalInteractf("%v", err)
}
if s.Type == "fail" {
return false, fmt.Errorf("client failed to request confirmation")
}
if err := expectStanzaWithNoBody(s, 1); err != nil {
return false, p.fatalInteractf("%v", err)
}
return s.Args[0] == "yes", nil
}
// fatalInteractf prints the error to stderr and sets the broken flag, so the
// Wrap/Unwrap caller can exit with an error.
func (p *Plugin) fatalInteractf(format string, args ...any) error {
p.broken = true
fmt.Fprintf(p.stderr, format, args...)
return fmt.Errorf(format, args...)
}
func (p *Plugin) fatalf(format string, args ...any) int {
fmt.Fprintf(p.stderr, format, args...)
return 1
}
func expectStanzaWithNoBody(s *format.Stanza, wantArgs int) error {
if len(s.Args) != wantArgs {
return fmt.Errorf("%s stanza has %d arguments, want %d", s.Type, len(s.Args), wantArgs)
}
if len(s.Body) != 0 {
return fmt.Errorf("%s stanza has %d bytes of body, want 0", s.Type, len(s.Body))
}
return nil
}
func expectStanzaWithBody(s *format.Stanza, wantArgs int) error {View on GitHub (pinned to b74dce4cdb)
Solutions
- Inspect the stderr output from the plugin — fatalInteractf prints the real underlying message there
- Verify the age client and plugin versions both implement the same plugin protocol version
- Run without output redirection to ensure the plugin's stdin/stdout protocol channel is intact
Defensive patterns
Strategy: try-catch
Validate before calling
// Before interaction, ensure the protocol pipes are unmodified: // (in plugin main) if os.Stdout has been redirected away from the client, abort early
Try / catch
if err != nil {
// fatalInteractf already printed the cause to the plugin's stderr;
// log err and mark the plugin broken so Wrap/Unwrap exits cleanly
return err
} Prevention
- Never redirect the plugin's stdin/stdout while it talks to the age client
- Keep age client and plugin protocol versions aligned
- Check plugin stderr output first when interactions fail
When it happens
Trigger: DisplayMessage, RequestValue, or Confirm reads a malformed/unexpected stanza from the client and calls fatalInteractf; readOkOrFail fails on a protocol violation; the client connection breaks mid-interaction.
Common situations: A buggy or too-old age client speaking a broken plugin protocol; the plugin's stdout/stderr being redirected causing protocol desync; corrupted interaction stream.
Related errors
- malformed recipient stanza: unexpected argument count
- malformed recipient stanza: invalid index
- malformed recipient stanza: unexpected index
- repeated labels stanza
- %s
AI-assisted analysis of FiloSottile/age@b74dce4cdb (2026-08-31).
Data as JSON: /api/errors/c66733ec6720e5af.
Report an issue: GitHub.