AlistGo/alist · warning
send failed
Error message
send failed
What it means
'send failed' is returned by (*Http).Send in internal/message/http.go when a non-blocking send on the unbuffered ToSend channel cannot proceed — i.e. no receiver is currently blocked reading from HttpInstance.ToSend. The select's default branch fires instead of blocking the caller.
Source
Thrown at internal/message/http.go:48
var req Req
if err := c.ShouldBind(&req); err != nil {
common.ErrorResp(c, err, 400)
return
}
select {
case p.Received <- req.Message:
common.SuccessResp(c)
default:
common.ErrorStrResp(c, "nowhere needed", 500)
}
}
func (p *Http) Send(message Message) error {
select {
case p.ToSend <- message:
return nil
default:
return errors.New("send failed")
}
}
func (p *Http) Receive() (string, error) {
select {
case message := <-p.Received:
return message, nil
default:
return "", errors.New("receive failed")
}
}
func (p *Http) WaitSend(message Message, d int) error {
select {
case p.ToSend <- message:
return nil
case <-time.After(time.Duration(d) * time.Second):
return errors.New("send timeout")View on GitHub (pinned to 843d9dc814)
Solutions
- Use WaitSend(message, d) instead of Send when the message may be produced before a poller is attached — it blocks up to d seconds for a receiver
- Ensure a consumer (the message-polling HTTP endpoint) is connected before producing messages
- Treat this error as 'message dropped, no consumer' and log/skip rather than retrying blindly
- If message delivery matters, switch to a buffered channel or a queue-backed mechanism
Example fix
// before err := message.HttpInstance.Send(msg) // after err := message.HttpInstance.WaitSend(msg, 5) // wait up to 5s for a poller
Defensive patterns
Strategy: fallback
Validate before calling
// establish a poller before producing messages // (client keeps the message long-poll active; server side:) go drainLoop()
Type guard
func isSendFailed(err error) bool {
return err != nil && err.Error() == "send failed"
} Try / catch
if err := message.HttpInstance.Send(msg); isSendFailed(err) {
// no consumer attached: drop or enqueue; never crash
} Prevention
- Prefer WaitSend with a bounded timeout over Send
- Keep the browser message poll connected before triggering notifications
- Treat this error as 'no consumer', not a fault
- Log at debug level to avoid noise
When it happens
Trigger: Calling HttpInstance.Send(msg) at a moment when no HTTP polling consumer is waiting in the receive branch that drains ToSend (the long-poll handler in the same file). Because the channel is unbuffered, a send only succeeds if a receiver is already parked on it.
Common situations: Frontend/browser tab not open or its message long-poll disconnected, so server-side code pushing a notification gets an immediate error; timing races where the message is produced just before the poll request arrives; multiple producers pushing while the single poller is between requests.
Related errors
AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15).
Data as JSON: /api/errors/5613513d2eb9e0f7.
Report an issue: GitHub.