FiloSottile/age · error

malformed file-key stanza: unexpected index

Error message

malformed file-key stanza: unexpected index

What it means

The file-key stanza's index parsed fine but was not 0. The age Go library always sends exactly one file to a plugin per invocation, so the only valid index is 0; any other index means the plugin is not following the v1 protocol.

Source

Thrown at plugin/client.go:278

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
			}
		case "error":
			if err := writeStanza(conn, "ok"); err != nil {
				return nil, err
			}

			return nil, fmt.Errorf("%s", s.Body)
		case "done":
			break ReadLoop

View on GitHub (pinned to b74dce4cdb)

Solutions

  1. Fix or update the plugin to always send index 0 (writeStanza(w, "file-key", "0"))
  2. Ensure only one file is submitted per plugin invocation — split multi-file work across invocations
  3. Confirm the plugin's protocol label (age-plugin v1) and behavior match what this library expects

Example fix

// before (plugin side)
writeStanza(w, "file-key", strconv.Itoa(fileIdx))
// after
writeStanza(w, "file-key", "0")
Defensive patterns

Strategy: validation

Validate before calling

// Ensure your tooling submits exactly one file per plugin invocation
if len(files) != 1 { return errors.New("plugin protocol supports one file per invocation") }

Try / catch

if err := unwrap(); err != nil {
    if strings.Contains(err.Error(), "unexpected index") {
        return fmt.Errorf("plugin is multi-file/misindexed; upgrade or replace plugin")
    }
}

Prevention

When it happens

Trigger: A plugin echoes back a nonzero file index (e.g. "file-key 1") in response to a recipient-v1 or identity-v1 unwrap performed via Unwrap.

Common situations: Plugins reused from tooling that batch multiple files per session; plugin code that increments or misreads the index counter; hand-written plugins that assume multi-file semantics.

Understand the failure class

Related errors


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