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

  1. 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
  2. Ensure a consumer (the message-polling HTTP endpoint) is connected before producing messages
  3. Treat this error as 'message dropped, no consumer' and log/skip rather than retrying blindly
  4. 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

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.