sipeed/picoclaw · error
feishu file send: %w
Error message
feishu file send: %w
What it means
After a successful file upload, the Message.Create that sends the file_key failed at transport level (network error, timeout, cancelled context). The underlying error is preserved with %w. As with images, a delayed retry risks the file_key expiring.
Source
Thrown at pkg/channels/feishu/feishu_64.go:1230
return fmt.Errorf("feishu file upload: no file_key returned")
}
fileKey := *uploadResp.Data.FileKey
// Send file message
content, _ := json.Marshal(map[string]string{"file_key": fileKey})
req := larkim.NewCreateMessageReqBuilder().
ReceiveIdType(larkim.CreateMessageV1ReceiveIDTypeChatId).
Body(larkim.NewCreateMessageReqBodyBuilder().
ReceiveId(chatID).
MsgType(larkim.MsgTypeFile).
Content(string(content)).
Build()).
Build()
resp, err := c.client.Im.V1.Message.Create(ctx, req)
if err != nil {
return fmt.Errorf("feishu file send: %w", err)
}
if !resp.Success() {
c.invalidateTokenOnAuthError(resp.Code)
return fmt.Errorf("feishu file send api error (code=%d msg=%s)", resp.Code, resp.Msg)
}
return nil
}
func extractFeishuSenderID(sender *larkim.EventSender) string {
if sender == nil || sender.SenderId == nil {
return ""
}
if sender.SenderId.UserId != nil && *sender.SenderId.UserId != "" {
return *sender.SenderId.UserId
}
if sender.SenderId.OpenId != nil && *sender.SenderId.OpenId != "" {
return *sender.SenderId.OpenIdView on GitHub (pinned to 49183d7e8d)
Solutions
- Unwrap the cause to confirm transport vs context cancellation.
- Retry the send; if it then reports an invalid file_key (see 492), redo upload+send as one unit.
- Use one generous deadline for the whole upload+send flow.
- Check egress stability for large payloads.
Example fix
// before
err := ch.SendMedia(ctx, msg)
// after
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
// caller cancelled or deadline hit: retry with fresh ctx and fresh file handle
}
var urlErr *url.Error
if errors.As(err, &urlErr) && urlErr.Timeout() {
// transport timeout: raise timeout, then retry upload+send together
} Defensive patterns
Strategy: retry
Validate before calling
mediaCtx, cancel := context.WithTimeout(ctx, 90*time.Second) // room for 30MB upload + send defer cancel()
Type guard
func isTimeout(err error) bool {
var urlErr *url.Error
return errors.As(err, &urlErr) && urlErr.Timeout()
} Try / catch
if err := ch.SendMedia(ctx, msg); err != nil {
if isTimeout(err) || errors.Is(err, context.Canceled) {
// retry the full upload+send; a lone send retry may hit an expired file_key
}
} Prevention
- One deadline for the whole media flow
- Pair upload+send in retries
- Keep the file available until send confirms
When it happens
Trigger: Connection drop or timeout between file upload and message send; ctx cancelled; SDK error building the msg_type=file request.
Common situations: Slow networks uploading near the 30MB cap then timing out on send; ctx deadline exhausted by the upload step; pod restart mid-flow.
Related errors
- feishu image send: %w
- feishu image upload: %w
- feishu image send api error (code=%d msg=%s)
- feishu file upload: %w
- feishu file send api error (code=%d msg=%s)
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/da08025ec5ed55ca.
Report an issue: GitHub.