FiloSottile/age · error

%s stanza has %d arguments, want %d

Error message

%s stanza has %d arguments, want %d

What it means

This error comes from the age plugin protocol client helper expectStanzaWithNoBody. It fires when a protocol stanza expected to carry exactly `wantArgs` arguments and no body instead carries a different number of space-separated arguments on its first line. The plugin protocol is line/stanza based, so argument counts are strict; a mismatch means the other side emitted a malformed stanza. It is a protocol-conformance failure, not a crypto failure.

Source

Thrown at plugin/plugin.go:590

	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 {
	if err := expectStanzaWithAnyBody(s, wantArgs); err != nil {
		return err
	}
	if len(s.Body) == 0 {
		return fmt.Errorf("%s stanza has 0 bytes of body, want >0", s.Type)
	}
	return nil
}

func expectStanzaWithAnyBody(s *format.Stanza, wantArgs int) error {

View on GitHub (pinned to b74dce4cdb)

Solutions

  1. Check the plugin binary version and upgrade or downgrade it so it matches the plugin protocol revision this library implements
  2. Print the raw stanza (s.Type and s.Args) at the failure point to see which argument was added or dropped
  3. If you wrote the plugin, fix the code that formats the reply so it emits exactly the required arguments with no extras
  4. If you control the harness, regenerate expected stanzas from the protocol spec

Example fix

// before (plugin side)
fmt.Printf("-> unsupported\n\n") // missing required argument

// after
fmt.Printf("-> unsupported %s\n\n", errReason)
Defensive patterns

Strategy: validation

Validate before calling

if len(stanza.Args) != wantArgs {
    return fmt.Errorf("plugin sent %s with %d args, want %d", stanza.Type, len(stanza.Args), wantArgs)
}

Type guard

func isWellFormedStanza(s *format.Stanza, wantArgs int) bool {
    return s != nil && len(s.Args) == wantArgs
}

Prevention

When it happens

Trigger: RecipientV1 or IdentityV1 received a reply stanza (ok, fail, unsupported, or a recipient/identity-specific stanza) whose Args slice length differs from the expected count; e.g. an 'ok' stanza with trailing arguments, or a 'unsupported' stanza where the plugin added an unexpected extra argument.

Common situations: Using a plugin binary that speaks a different (older/newer) plugin protocol revision than this client expects; a buggy third-party age plugin that appends extra fields; a hand-rolled test harness emitting stanzas with wrong argument counts; whitespace/quoting bugs when the plugin builds its reply line.

Related errors


AI-assisted analysis of FiloSottile/age@b74dce4cdb (2026-08-31). Data as JSON: /api/errors/5e589868467292b9. Report an issue: GitHub.