{"record":{"id":"c66733ec6720e5af","repo":"FiloSottile/age","slug":"v","errorCode":null,"errorMessage":"%v","messagePattern":"%v","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/plugin.go","lineNumber":580,"sourceCode":"\ts, err = readOkOrFail(p.sr)\n\tif err != nil {\n\t\treturn false, p.fatalInteractf(\"%v\", err)\n\t}\n\tif s.Type == \"fail\" {\n\t\treturn false, fmt.Errorf(\"client failed to request confirmation\")\n\t}\n\tif err := expectStanzaWithNoBody(s, 1); err != nil {\n\t\treturn false, p.fatalInteractf(\"%v\", err)\n\t}\n\treturn s.Args[0] == \"yes\", nil\n}\n\n// fatalInteractf prints the error to stderr and sets the broken flag, so the\n// Wrap/Unwrap caller can exit with an error.\nfunc (p *Plugin) fatalInteractf(format string, args ...any) error {\n\tp.broken = true\n\tfmt.Fprintf(p.stderr, format, args...)\n\treturn fmt.Errorf(format, args...)\n}\n\nfunc (p *Plugin) fatalf(format string, args ...any) int {\n\tfmt.Fprintf(p.stderr, format, args...)\n\treturn 1\n}\n\nfunc expectStanzaWithNoBody(s *format.Stanza, wantArgs int) error {\n\tif len(s.Args) != wantArgs {\n\t\treturn fmt.Errorf(\"%s stanza has %d arguments, want %d\", s.Type, len(s.Args), wantArgs)\n\t}\n\tif len(s.Body) != 0 {\n\t\treturn fmt.Errorf(\"%s stanza has %d bytes of body, want 0\", s.Type, len(s.Body))\n\t}\n\treturn nil\n}\n\nfunc expectStanzaWithBody(s *format.Stanza, wantArgs int) error {","sourceCodeStart":562,"sourceCodeEnd":598,"githubUrl":"https://github.com/FiloSottile/age/blob/b74dce4cdbe35b5e5f66c06d9612b72f89028758/plugin/plugin.go#L562-L598","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Before interaction, ensure the protocol pipes are unmodified:\n// (in plugin main) if os.Stdout has been redirected away from the client, abort early","typeGuard":null,"tryCatchPattern":"if err != nil {\n    // fatalInteractf already printed the cause to the plugin's stderr;\n    // log err and mark the plugin broken so Wrap/Unwrap exits cleanly\n    return err\n}","preventionTips":["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"],"tags":["age","plugin","protocol","interaction"],"backgroundTag":"plugin-protocol-broken","analyzedSha":"b74dce4cdbe35b5e5f66c06d9612b72f89028758","analyzedAt":"2026-08-31T23:59:31.627Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}