sipeed/picoclaw · error
feishu file upload: %w
Error message
feishu file upload: %w
What it means
The file upload call Im.V1.File.Create failed at transport level before the API answered — network failure, timeout, or an unusable *os.File. The underlying error is preserved with %w. Feishu file uploads are larger than images (limit 30MB), so client timeouts are the most common cause.
Source
Thrown at pkg/channels/feishu/feishu_64.go:1205
switch fileType {
case "audio":
feishuFileType = "opus"
case "video":
feishuFileType = "mp4"
}
// Upload file to get file_key
uploadReq := larkim.NewCreateFileReqBuilder().
Body(larkim.NewCreateFileReqBodyBuilder().
FileType(feishuFileType).
FileName(filename).
File(file).
Build()).
Build()
uploadResp, err := c.client.Im.V1.File.Create(ctx, uploadReq)
if err != nil {
return fmt.Errorf("feishu file upload: %w", err)
}
if !uploadResp.Success() {
c.invalidateTokenOnAuthError(uploadResp.Code)
return fmt.Errorf("feishu file upload api error (code=%d msg=%s)", uploadResp.Code, uploadResp.Msg)
}
if uploadResp.Data == nil || uploadResp.Data.FileKey == nil {
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).View on GitHub (pinned to 49183d7e8d)
Solutions
- Unwrap the cause with errors.As (*url.Error, *net.OpError, *fs.PathError) to separate network from file issues.
- Confirm the file handle is open and seeked to offset 0 before sendFile.
- Raise the Lark client timeout for file uploads or compress/split files under 30MB.
- Verify egress/proxy from the runtime host.
Example fix
// before
err := ch.SendMedia(ctx, msg)
// after
var opErr *net.OpError
if errors.As(err, &opErr) {
// transport-level: safe to retry the whole upload with a fresh file handle
}
var pathErr *fs.PathError
if errors.As(err, &pathErr) {
// local file problem: reopen/rewind the file before retrying
} Defensive patterns
Strategy: retry
Validate before calling
if _, serr := file.Stat(); serr != nil {
return fmt.Errorf("file unusable: %w", serr)
}
if fi, _ := file.Stat(); fi.Size() > 30<<20 {
return fmt.Errorf("file exceeds Feishu 30MB limit")
}
file.Seek(0, io.SeekStart) Type guard
func isTransportErr(err error) bool {
var opErr *net.OpError
return errors.As(err, &opErr)
} Try / catch
err := ch.SendMedia(ctx, msg)
if err != nil {
var pathErr *fs.PathError
if errors.As(err, &pathErr) {
// local file problem: reopen before retrying — retry alone will not fix it
} else if isTransportErr(err) {
// network: safe to retry with the same handle
}
} Prevention
- Pre-check 30MB limit before upload
- Open fresh handles per attempt
- Raise client timeout for file-size uploads
- Compress or split large attachments
When it happens
Trigger: DNS/egress failure to open.feishu.cn; file handle nil/closed/EOF; client timeout uploading a tens-of-MB file on a slow link; ctx cancelled mid-upload.
Common situations: Sending large attachments (logs, media) over constrained uplinks; temp file deleted by cleanup while still open; pod network policy blocking egress mid-session.
Related errors
- feishu image upload: %w
- feishu image send: %w
- feishu file send: %w
- feishu send text: %w
- feishu image upload api error (code=%d msg=%s)
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/421a2fd8afe9b5c8.
Report an issue: GitHub.