FiloSottile/age · error
client failed to request confirmation
Error message
client failed to request confirmation
What it means
Confirm asks the age client to display a yes/no confirmation to the user via the confirm protocol command. This error means the client responded with a "fail" stanza — it could not present the confirmation or obtain an answer, so the plugin cannot know the user's choice.
Source
Thrown at plugin/plugin.go:567
// selected the yes or no option. Confirm returns an error if the client can't
// request the confirmation.
//
// It must only be called by a Wrap or Unwrap method invoked by [Plugin.Main].
func (p *Plugin) Confirm(prompt, yes, no string) (choseYes bool, err error) {
args := []string{format.EncodeToString([]byte(yes))}
if no != "" {
args = append(args, format.EncodeToString([]byte(no)))
}
s := &format.Stanza{Type: "confirm", Args: args, Body: []byte(prompt)}
if err := s.Marshal(p.stdout); err != nil {
return false, p.fatalInteractf("failed to write confirm stanza: %v", err)
}
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 1View on GitHub (pinned to b74dce4cdb)
Solutions
- Proceed with a safe default or let the operation fail explicitly when the confirmation cannot be shown, depending on security requirements
- Run the workflow in an interactive environment where the client UI can confirm
- Upgrade the age client to one that supports the confirm command
Example fix
// before
ok, err := p.Confirm("touch device", "proceed without touch?")
if err != nil { return err }
// after
ok, err := p.Confirm("touch device", "proceed without touch?")
if err != nil {
return fmt.Errorf("cannot confirm user intent: %w", err) // fail closed
} Defensive patterns
Strategy: fallback
Validate before calling
// Only call Confirm when an interactive client is available:
// if !interactiveSession { use safe default instead of Confirm } Try / catch
ok, err := p.Confirm(question, fallbackQuestion)
if err != nil {
// fail closed or apply documented default
return fmt.Errorf("confirmation unavailable: %w", err)
} Prevention
- Decide and document fail-open vs fail-closed behavior for missing confirmations
- Avoid GUI-dependent plugins in headless jobs
- Upgrade age clients to support the confirm command
When it happens
Trigger: The client has no way to show a yes/no dialog (headless run, unsupported client version); the client refuses the confirm request; the interaction channel is in a state where the client returns fail.
Common situations: Hardware-token plugins asking "touch your key / insert device" during CI or SSH sessions without an agent UI; older age clients lacking confirm support; scripting age where all UI is suppressed.
Related errors
- client failed to display message
- client failed to request value
- %s plugin: %w
- couldn't start plugin: %w
- malformed recipient stanza: unexpected argument count
AI-assisted analysis of FiloSottile/age@b74dce4cdb (2026-08-31).
Data as JSON: /api/errors/43f6496b0d5d1e76.
Report an issue: GitHub.