{"record":{"id":"2d70a795f4f8b650","repo":"sipeed/picoclaw","slug":"no-media-store-available-w-2d70a7","errorCode":null,"errorMessage":"no media store available: %w","messagePattern":"no media store available: %w","errorType":"exception","errorClass":"ErrSendFailed","httpStatus":null,"severity":"error","filePath":"pkg/channels/feishu/feishu_64.go","lineNumber":501,"sourceCode":"\t}\n\treturn undo, nil\n}\n\n// SendMedia implements channels.MediaSender.\n// Uploads images/files via Feishu API then sends as messages.\nfunc (c *FeishuChannel) SendMedia(ctx context.Context, msg bus.OutboundMediaMessage) ([]string, error) {\n\tif !c.IsRunning() {\n\t\treturn nil, channels.ErrNotRunning\n\t}\n\ttrackedMsgID, hasTrackedMsg := c.currentToolFeedbackMessage(msg.ChatID)\n\n\tif msg.ChatID == \"\" {\n\t\treturn nil, fmt.Errorf(\"chat ID is empty: %w\", channels.ErrSendFailed)\n\t}\n\n\tstore := c.GetMediaStore()\n\tif store == nil {\n\t\treturn nil, fmt.Errorf(\"no media store available: %w\", channels.ErrSendFailed)\n\t}\n\n\tcaption := firstMediaCaption(msg.Parts)\n\tsentAny := false\n\tfor _, part := range msg.Parts {\n\t\tif err := c.sendMediaPartFn(ctx, msg.ChatID, part, store); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tsentAny = true\n\t}\n\tif sentAny && caption != \"\" {\n\t\tif _, err := c.sendTextFn(ctx, msg.ChatID, caption); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tif hasTrackedMsg {\n\t\tc.dismissTrackedToolFeedbackMessage(ctx, msg.ChatID, trackedMsgID)","sourceCodeStart":483,"sourceCodeEnd":519,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/channels/feishu/feishu_64.go#L483-L519","documentation":"FeishuChannel.SendMedia requires a media store (to fetch/cache the bytes of each media part) and got nil from GetMediaStore(). This is a wiring/dependency error, not a runtime one: the channel was composed without a media store, so every media send will fail. Wrapped with the permanent ErrSendFailed sentinel.","triggerScenarios":"SendMedia is invoked on a FeishuChannel whose media store was never injected (GetMediaStore() == nil) - typically a custom composition root or test harness that constructs the channel directly instead of via the standard bootstrap.","commonSituations":"Embedding the channel in your own main() and forgetting SetMediaStore; DI container misconfiguration; feature-flagged media support disabled at composition time but media messages still routed to the channel.","solutions":["Wire a media store into the channel during composition (SetMediaStore / the package's bootstrap helper) before dispatching media","Assert media readiness at startup: fail fast if media messages can reach a channel without a store","Until wired, route media replies to a text fallback instead of sending to this channel"],"exampleFix":"// before\nch, _ := feishu.NewFeishuChannel(cfg) // no media store wired\nbus.SubscribeMedia(ch.SendMedia) // every media send fails\n\n// after\nch, _ := feishu.NewFeishuChannel(cfg)\nch.SetMediaStore(mystore) // injected at composition\nbus.SubscribeMedia(ch.SendMedia)","handlingStrategy":"validation","validationCode":"// capability check at composition time, before any message flows\nif !ch.HasMediaStore() { // or: ch.GetMediaStore() == nil via the public interface\n\tlogger.Fatal(\"feishu channel used for media without a media store\")\n}\nbus.SubscribeMedia(ch.SendMedia)","typeGuard":"null","tryCatchPattern":"if err := ch.SendMedia(ctx, msg); err != nil {\n\tif errors.Is(err, channels.ErrSendFailed) && strings.Contains(err.Error(), \"no media store\") {\n\t\t// wiring bug: fall back to text-only notice instead of failing silently\n\t\t_, _ = ch.Send(ctx, bus.OutboundMessage{ChatID: msg.ChatID, Content: \"[media unavailable]\"})\n\t\treturn nil\n\t}\n\treturn err\n}","preventionTips":["Assert required dependencies at composition time (fail fast, not on first media send)","Reuse the package's bootstrap helper rather than constructing channels manually","Add a startup self-test that sends/round-trips a tiny media message in staging","Make wiring bugs loud: this error repeats for every media message until fixed"],"tags":["feishu","dependency-injection","media","wiring","send-failed"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}