m1k1o/neko · warning
receiver session ID not found
Error message
receiver session ID not found
What it means
sendUnicast relays a private message from one session to another over the neko websocket. Before delivering, it looks up the target session by ID in the session manager (h.sessions.Get); if no session with payload.Receiver exists it throws this error and the message is not delivered. It is a client-addressing error: the sender referenced a session that has disconnected or never existed.
Source
Thrown at server/internal/websocket/handler/send.go:14
package handler
import (
"errors"
"github.com/m1k1o/neko/server/pkg/types"
"github.com/m1k1o/neko/server/pkg/types/event"
"github.com/m1k1o/neko/server/pkg/types/message"
)
func (h *MessageHandlerCtx) sendUnicast(session types.Session, payload *message.SendUnicast) error {
receiver, ok := h.sessions.Get(payload.Receiver)
if !ok {
return errors.New("receiver session ID not found")
}
receiver.Send(
event.SEND_UNICAST,
message.SendUnicast{
Sender: session.ID(),
Receiver: receiver.ID(),
Subject: payload.Subject,
Body: payload.Body,
})
return nil
}
func (h *MessageHandlerCtx) sendBroadcast(session types.Session, payload *message.SendBroadcast) error {
h.sessions.Broadcast(
event.SEND_BROADCAST,
message.SendBroadcast{View on GitHub (pinned to b0f01cedea)
Solutions
- Check the receiver session ID is current: fetch the live session list and verify the target session still exists before sending
- Fall back to a broadcast message if the target is gone, or surface 'user not in room' to the sender
- Re-fetch session IDs after any reconnect instead of caching old ones
- Handle the error per-message (log/skip) instead of failing the whole send loop
Example fix
// before
h.websocket.Send(types.Message{Payload: message.SendUnicast{Receiver: cachedID, ...}})
// after
if _, ok := sessionList[cachedID]; ok {
h.websocket.Send(types.Message{Payload: message.SendUnicast{Receiver: cachedID, ...}})
} else {
notifySender("receiver not in room")
} Defensive patterns
Strategy: validation
Validate before calling
func canSend(sessions types.SessionManager, receiverID string) bool {
_, ok := sessions.Get(receiverID)
return ok
} Type guard
func receiverExists(sessions types.SessionManager, id string) bool {
_, ok := sessions.Get(id)
return ok
} Try / catch
err := handler.Send(...)
if err != nil && err.Error() == "receiver session ID not found" {
// drop message or notify sender that the user is offline
} Prevention
- Always fetch fresh session IDs from the session manager before unicast
- Never cache session IDs across reconnects
- Treat unicast as best-effort and handle per-message failures
- Verify membership before sending targeted messages
When it happens
Trigger: Client sends a SEND_UNICAST websocket message whose 'receiver' field contains a session ID that is not currently registered — e.g. the target user disconnected, the ID was mistyped or stale, or the message races with the target's disconnect.
Common situations: Chat/plugins sending private messages to a user who just left the room; caching a peer's session ID across reconnects (IDs change on reconnect); broadcasting to a hardcoded ID; race between fetching a member list and sending.
Related errors
- session is already connected
- no authentication provided
- session token already exists
- cannot access clipboard
- is not the host
AI-assisted analysis of m1k1o/neko@b0f01cedea (2026-09-01).
Data as JSON: /api/errors/67b5653e8372a55c.
Report an issue: GitHub.