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

  1. Check the receiver session ID is current: fetch the live session list and verify the target session still exists before sending
  2. Fall back to a broadcast message if the target is gone, or surface 'user not in room' to the sender
  3. Re-fetch session IDs after any reconnect instead of caching old ones
  4. 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

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


AI-assisted analysis of m1k1o/neko@b0f01cedea (2026-09-01). Data as JSON: /api/errors/67b5653e8372a55c. Report an issue: GitHub.