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

  1. Verify fileKey is non-empty before building the message (re-add the 1237 guard if removed)
  2. Pin the lark SDK version known to work with this platform version
  3. Rebuild from a clean checkout to eliminate patched SDK code
  4. 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

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


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/c5e12114e7cad6e2. Report an issue: GitHub.