FiloSottile/age · error
expected ok or fail stanza, got %q
Error message
expected ok or fail stanza, got %q
What it means
readOkOrFail accepts only 'ok' or 'fail' as the reply to an interactive command; any other stanza type produces this error naming the unexpected type. The plugin responded with a stanza that does not fit the request/response contract for DisplayMessage, RequestValue, or Confirm.
Source
Thrown at plugin/plugin.go:654
}
return expectStanzaWithNoBody(ok, 0)
}
func readOkOrFail(sr *format.StanzaReader) (*format.Stanza, error) {
s, err := sr.ReadStanza()
if err != nil {
return nil, fmt.Errorf("failed to read response stanza: %v", err)
}
switch s.Type {
case "fail":
if err := expectStanzaWithNoBody(s, 0); err != nil {
return nil, fmt.Errorf("%v", err)
}
return s, nil
case "ok":
return s, nil
default:
return nil, fmt.Errorf("expected ok or fail stanza, got %q", s.Type)
}
}
func expectUnsupported(sr *format.StanzaReader) error {
unsupported, err := sr.ReadStanza()
if err != nil {
return fmt.Errorf("failed to read unsupported stanza: %v", err)
}
if unsupported.Type != "unsupported" {
return fmt.Errorf("expected unsupported stanza, got %q", unsupported.Type)
}
return expectStanzaWithNoBody(unsupported, 0)
}
func (p *Plugin) writeError(args []string, err error) error {
s := &format.Stanza{Type: "error", Args: args}
s.Body = []byte(err.Error())
if err := s.Marshal(p.stdout); err != nil {View on GitHub (pinned to b74dce4cdb)
Solutions
- Check which stanza type was received (it is quoted in the error) and map it to the plugin's behavior
- Confirm the plugin advertises support for the interactive command being issued
- Upgrade the plugin; if it cannot support the command it must reply 'fail', not an arbitrary stanza
- Ensure plugin diagnostics go to stderr so they never pollute the stanza stream
Example fix
// before (plugin side)
fmt.Printf("-> maybe\n\n")
// after
fmt.Printf("-> fail\n\n") // or "-> ok\n\n" Defensive patterns
Strategy: type-guard
Type guard
func isOkOrFail(s *format.Stanza) bool {
return s != nil && (s.Type == "ok" || s.Type == "fail")
} Try / catch
s, err := readOkOrFail(sr)
if err != nil {
if strings.HasPrefix(err.Error(), "expected ok or fail stanza") {
return fmt.Errorf("plugin does not support this interactive command: %w", err)
}
return err
} Prevention
- Reply 'fail' (not an arbitrary stanza) when a command is unsupported
- Never echo user input or logs onto the protocol stdout
- Sequence commands strictly one request per one reply
When it happens
Trigger: A plugin replies with a data stanza, 'unsupported', or a custom type where the client demanded 'ok'/'fail'; command sequencing desynchronized so a stale stanza from an earlier exchange is read here.
Common situations: Plugin not implementing the interactive-message protocol (responds 'unsupported' to a display-message/command); protocol version skew; plugin echoing input or diagnostics onto stdout that the reader interprets as a stanza.
Related errors
- expected OK stanza, got %q
- %s stanza has %d arguments, want %d
- %s stanza has %d bytes of body, want 0
- %s stanza has 0 bytes of body, want >0
- invalid ssh-rsa recipient block
AI-assisted analysis of FiloSottile/age@b74dce4cdb (2026-08-31).
Data as JSON: /api/errors/16a5f09cc40e846a.
Report an issue: GitHub.