FiloSottile/age · error

malformed file-key stanza: unexpected arguments count

Error message

malformed file-key stanza: unexpected arguments count

What it means

During age plugin unwrapping, the client parses a 'file-key' stanza sent by the plugin binary. This error means the stanza carried a number of arguments other than exactly one (the file-key index). The age plugin protocol v1 requires the file-key stanza to have exactly one argument, so the client rejects anything else as a protocol violation.

Source

Thrown at plugin/client.go:270

		}
	}
	if err := writeStanza(conn, "done"); err != nil {
		return nil, err
	}

	// Phase 2: plugin responds with various commands and a file key
	sr := format.NewStanzaReader(bufio.NewReader(conn))
ReadLoop:
	for {
		s, err := i.ui.readStanza(i.name, sr)
		if err != nil {
			return nil, err
		}

		switch s.Type {
		case "file-key":
			if len(s.Args) != 1 {
				return nil, fmt.Errorf("malformed file-key stanza: unexpected arguments count")
			}
			n, err := strconv.Atoi(s.Args[0])
			if err != nil {
				return nil, fmt.Errorf("malformed file-key stanza: invalid index")
			}
			// We only send a single file key, so the index must be 0.
			if n != 0 {
				return nil, fmt.Errorf("malformed file-key stanza: unexpected index")
			}
			if fileKey != nil {
				return nil, fmt.Errorf("received duplicated file-key stanza")
			}

			fileKey = s.Body

			if err := writeStanza(conn, "ok"); err != nil {
				return nil, err
			}

View on GitHub (pinned to b74dce4cdb)

Solutions

  1. Update the plugin binary to a version that conforms to the age-plugin protocol v1 (exactly one argument in the file-key stanza)
  2. Check which plugin binary is being resolved for AGE-PLUGIN-<name>-1 identities (age-plugin-<name> on PATH / testOnlyPluginPath) and remove shadowing scripts
  3. If you wrote the plugin, fix its Unwrap loop to send writeStanza(w, "file-key", "0") with a single argument
  4. Verify the recipient/identity stanza name matches the plugin actually handling it; a mismatched plugin may answer with stanzas it shouldn't

Example fix

// before (plugin side)
writeStanza(w, "file-key", "0", "extra")
// after
writeStanza(w, "file-key", "0")
Defensive patterns

Strategy: validation

Validate before calling

// Client can't pre-validate plugin output; validate the plugin before use.
out, err := exec.Command("age-plugin-foo", "--age-plugin=recipient-v1").Output()
if err != nil { log.Fatalf("plugin broken: %v", err) }

Try / catch

if _, err := identity.Unwrap(...); err != nil {
    if strings.Contains(err.Error(), "malformed file-key stanza") {
        // treat plugin as incompatible: report version, suggest upgrade
    }
}

Prevention

When it happens

Trigger: A plugin binary writes a 'file-key' stanza with zero or two or more space-separated arguments (e.g. writeStanza(conn, "file-key", args...) called with wrong arity) while the client's Unwrap/UnwrapWithLabels is reading its response.

Common situations: Custom or third-party age plugins that hand-roll the plugin protocol and emit a malformed file-key stanza; plugin versions that predate or diverge from the v1 protocol; a plugin binary on PATH that is actually a different/older program responding with an unexpected format.

Understand the failure class

Related errors


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