chenhg5/cc-connect · error
%s: build audio message: %w
Error message
%s: build audio message: %w
What it means
SendAudio serializes the larkim.MessageAudio struct (containing the uploaded file_key) into the message JSON content via audioMsg.String(). This error wraps a failure of that serialization. It is rare — it only fires if the audio message struct cannot be marshalled to Feishu's content JSON, usually due to an SDK version mismatch or an empty/invalid file_key.
Source
Thrown at platform/feishu/feishu.go:5512
if !uploadResp.Success() {
return fmt.Errorf("%s: upload audio code=%d msg=%s", p.tag(), uploadResp.Code, uploadResp.Msg)
}
return nil
})
}); err != nil {
return err
}
if uploadResp.Data == nil || uploadResp.Data.FileKey == nil {
return fmt.Errorf("%s: upload audio: no file_key returned", p.tag())
}
fileKey := *uploadResp.Data.FileKey
slog.Debug(p.tag()+": audio uploaded", "file_key", fileKey, "format", format, "size", len(audio))
audioMsg := larkim.MessageAudio{FileKey: fileKey}
audioContent, err := audioMsg.String()
if err != nil {
return fmt.Errorf("%s: build audio message: %w", p.tag(), err)
}
// Diagnostic for QA-reported intermittent "audio rendered as file" in
// P2P reply mode (see internal task t-20260615-cqjbk1). Tracking the
// API path lets operators correlate Feishu client renders to whether
// we used Reply (in-thread) or Create (new message) when issues
// recur. The Reply path has historically had narrower MsgType
// support on some Feishu desktop client versions.
if p.shouldUseThreadOrReplyAPI(rc) {
slog.Debug(p.tag()+": SendAudio using Reply API",
"file_key", fileKey, "msg_id", rc.messageID, "format", format)
} else {
slog.Debug(p.tag()+": SendAudio using Create API",
"file_key", fileKey, "chat_id", rc.chatID, "format", format)
}
return p.sendMediaMessage(ctx, rc, larkim.MsgTypeAudio, audioContent)
}View on GitHub (pinned to 4000b2338a)
Solutions
- Verify fileKey is non-empty before building the message (re-add the 1237 guard if removed)
- Pin the lark SDK version known to work with this platform version
- Rebuild from a clean checkout to eliminate patched SDK code
- Log fileKey and the wrapped error to confirm which field is invalid
Example fix
// before
audioMsg := larkim.MessageAudio{FileKey: fileKey}
audioContent, err := audioMsg.String()
// after
if fileKey == "" { return fmt.Errorf("%s: empty file_key before building audio message", p.tag()) }
audioMsg := larkim.MessageAudio{FileKey: fileKey}
audioContent, err := audioMsg.String() Defensive patterns
Strategy: validation
Validate before calling
if fileKey == "" { return errors.New("cannot build audio message: empty file_key") } Try / catch
audioContent, err := audioMsg.String()
if err != nil {
slog.Error("feishu: audio content marshal failed", "fileKey", fileKey, "err", err)
return fmt.Errorf("send audio: %w", err)
} Prevention
- Validate fileKey before constructing MessageAudio
- Pin working lark SDK versions
- Avoid forked/patched SDK code
- Test audio send after every SDK upgrade
When it happens
Trigger: audioMsg.String() returns a non-nil error: nil or empty FileKey produced an invalid content payload, or the installed lark SDK's MessageAudio.String has a marshalling bug/changed contract.
Common situations: A previous step silently produced an empty file_key (e.g. altered validation removed the 1237 check); SDK upgrade changed MessageAudio's schema; hand-patched fork of the SDK.
Understand the failure class
Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.
Related errors
- %s: upload image: no image_key returned
- %s: upload file: no file_key returned
- %s: SendAudio: invalid reply context type %T
- %s: convert to opus: %w
- %s: upload audio: %w
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/c5e12114e7cad6e2.
Report an issue: GitHub.