{"record":{"id":"421a2fd8afe9b5c8","repo":"sipeed/picoclaw","slug":"feishu-file-upload-w","errorCode":null,"errorMessage":"feishu file upload: %w","messagePattern":"feishu file upload: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/channels/feishu/feishu_64.go","lineNumber":1205,"sourceCode":"\tswitch fileType {\n\tcase \"audio\":\n\t\tfeishuFileType = \"opus\"\n\tcase \"video\":\n\t\tfeishuFileType = \"mp4\"\n\t}\n\n\t// Upload file to get file_key\n\tuploadReq := larkim.NewCreateFileReqBuilder().\n\t\tBody(larkim.NewCreateFileReqBodyBuilder().\n\t\t\tFileType(feishuFileType).\n\t\t\tFileName(filename).\n\t\t\tFile(file).\n\t\t\tBuild()).\n\t\tBuild()\n\n\tuploadResp, err := c.client.Im.V1.File.Create(ctx, uploadReq)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"feishu file upload: %w\", err)\n\t}\n\tif !uploadResp.Success() {\n\t\tc.invalidateTokenOnAuthError(uploadResp.Code)\n\t\treturn fmt.Errorf(\"feishu file upload api error (code=%d msg=%s)\", uploadResp.Code, uploadResp.Msg)\n\t}\n\tif uploadResp.Data == nil || uploadResp.Data.FileKey == nil {\n\t\treturn fmt.Errorf(\"feishu file upload: no file_key returned\")\n\t}\n\n\tfileKey := *uploadResp.Data.FileKey\n\n\t// Send file message\n\tcontent, _ := json.Marshal(map[string]string{\"file_key\": fileKey})\n\treq := larkim.NewCreateMessageReqBuilder().\n\t\tReceiveIdType(larkim.CreateMessageV1ReceiveIDTypeChatId).\n\t\tBody(larkim.NewCreateMessageReqBodyBuilder().\n\t\t\tReceiveId(chatID).\n\t\t\tMsgType(larkim.MsgTypeFile).","sourceCodeStart":1187,"sourceCodeEnd":1223,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/channels/feishu/feishu_64.go#L1187-L1223","documentation":"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.","triggerScenarios":"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.","commonSituations":"Sending large attachments (logs, media) over constrained uplinks; temp file deleted by cleanup while still open; pod network policy blocking egress mid-session.","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."],"exampleFix":"// before\nerr := ch.SendMedia(ctx, msg)\n\n// after\nvar opErr *net.OpError\nif errors.As(err, &opErr) {\n    // transport-level: safe to retry the whole upload with a fresh file handle\n}\nvar pathErr *fs.PathError\nif errors.As(err, &pathErr) {\n    // local file problem: reopen/rewind the file before retrying\n}","handlingStrategy":"retry","validationCode":"if _, serr := file.Stat(); serr != nil {\n    return fmt.Errorf(\"file unusable: %w\", serr)\n}\nif fi, _ := file.Stat(); fi.Size() > 30<<20 {\n    return fmt.Errorf(\"file exceeds Feishu 30MB limit\")\n}\nfile.Seek(0, io.SeekStart)","typeGuard":"func isTransportErr(err error) bool {\n    var opErr *net.OpError\n    return errors.As(err, &opErr)\n}","tryCatchPattern":"err := ch.SendMedia(ctx, msg)\nif err != nil {\n    var pathErr *fs.PathError\n    if errors.As(err, &pathErr) {\n        // local file problem: reopen before retrying — retry alone will not fix it\n    } else if isTransportErr(err) {\n        // network: safe to retry with the same handle\n    }\n}","preventionTips":["Pre-check 30MB limit before upload","Open fresh handles per attempt","Raise client timeout for file-size uploads","Compress or split large attachments"],"tags":["feishu","upload","go","network","file-io"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}