FiloSottile/age · error
received duplicated file-key stanza
Error message
received duplicated file-key stanza
What it means
The plugin sent a second file-key stanza within one unwrap session. The client already received and acknowledged one file key; the protocol allows only one per invocation, so a duplicate indicates a buggy plugin that is answering the same request twice.
Source
Thrown at plugin/client.go:281
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
default:
if ok, err := i.ui.handle(i.name, conn, s); err != nil {
return nil, errView on GitHub (pinned to b74dce4cdb)
Solutions
- Update the plugin to send the file-key stanza exactly once per session, then wait for "done"
- Audit the plugin's state machine: after replying to file-key it should only send "error" or "done"
- Test the plugin against age-plugin-test-tool or the official age client to catch duplicate stanzas
Example fix
// before (plugin side)
for { handleStanza(); if isFileKey { sendFileKey() } } // loops forever
// after
handleFileKeyRequest(); sendFileKey(); awaitDone() Defensive patterns
Strategy: validation
Validate before calling
// In plugin code, assert single-send before writing file-key
if sent { t.Fatal("file-key sent twice") }; sent = true Try / catch
err := identity.Unwrap(...)
if err != nil && strings.Contains(err.Error(), "duplicated file-key") {
return fmt.Errorf("plugin %s sent file-key twice; plugin state machine bug", pluginName)
} Prevention
- Structure plugin unwrap as: read stanza -> answer once -> await done
- Add integration tests asserting one file-key per session
- Use the age-plugin-test-tool to catch protocol violations
When it happens
Trigger: During Unwrap, the plugin writes "file-key" again after the client has already stored fileKey and replied with an "ok" stanza.
Common situations: Plugin loops that don't break after answering the file-key request; plugin handling both wrap and unwrap paths incorrectly; a plugin that retries internally after a slow "ok" acknowledgment.
Related errors
- malformed file-key stanza: unexpected arguments count
- malformed file-key stanza: invalid index
- malformed file-key stanza: unexpected index
- malformed confirm stanza: unexpected number of arguments
- malformed confirm stanza: invalid YES option encoding
AI-assisted analysis of FiloSottile/age@b74dce4cdb (2026-08-31).
Data as JSON: /api/errors/d275d40c1c3fdf9b.
Report an issue: GitHub.