m1k1o/neko · warning

session not found

Error message

session not found

What it means

This error is returned by LegacyHandler.ban when a ban request references a sessionId that is not present in the handler's in-memory sessionIPs map. The legacy handler only records session-to-IP mappings when a session registers locally, so banning an unknown, already-disconnected, or never-seen session id yields this error. It is a client-side lookup failure within the proxy, not a backend failure.

Source

Thrown at server/internal/http/legacy/handler.go:433

			return utils.HttpInternalServerError().WithInternalErr(err)
		}

		// copy the body to the response writer
		_, err = io.Copy(w, body)
		return err
	})

	r.Get("/health", func(w http.ResponseWriter, r *http.Request) error {
		_, err := w.Write([]byte("true"))
		return err
	})
}

func (h *LegacyHandler) ban(sessionId string) error {
	// find session by id
	ip, ok := h.sessionIPs[sessionId]
	if !ok {
		return fmt.Errorf("session not found")
	}

	h.bannedIPs[ip] = struct{}{}
	return nil
}

func (h *LegacyHandler) isBanned(r *http.Request) bool {
	ip := getIp(r)
	_, ok := h.bannedIPs[ip]
	return ok
}

func getIp(r *http.Request) string {
	ip, _, err := net.SplitHostPort(r.RemoteAddr)
	if err != nil {
		if e, ok := err.(*net.AddrError); ok && e.Err == "missing port in address" {
			return r.RemoteAddr
		}

View on GitHub (pinned to b0f01cedea)

Solutions

  1. Verify the sessionId exists before banning by checking the sessions list (GET /api/sessions via apiReq).
  2. Deploy sticky routing or a shared session registry so the ban reaches the node owning the session.
  3. Handle the error gracefully in wsToBackend: log and skip instead of failing the moderation flow.
  4. If restarts lose mappings, persist sessionIPs or re-derive IP from the backend API instead of local memory.

Example fix

// before
ip, ok := h.sessionIPs[sessionId]
if !ok {
    return fmt.Errorf("session not found")
}
// after
ip, ok := h.sessionIPs[sessionId]
if !ok {
    log.Warn().Str("sessionId", sessionId).Msg("ban skipped: session not found on this node")
    return nil // or a typed ErrSessionNotFound
}
Defensive patterns

Strategy: validation

Validate before calling

if _, ok := handler.sessionIPs[sessionId]; !ok {
    return fmt.Errorf("cannot ban %q: session not registered on this node", sessionId)
}

Type guard

func sessionKnown(h *LegacyHandler, sessionId string) bool {
    _, ok := h.sessionIPs[sessionId]
    return ok
}

Try / catch

if err := h.ban(id); err != nil {
    if err.Error() == "session not found" {
        log.Warn().Str("sessionId", id).Msg("ban skipped: session not on this node")
        return nil
    }
    return err
}

Prevention

When it happens

Trigger: Calling LegacyHandler.ban(sessionId) with an id never registered in h.sessionIPs — e.g. wsToBackend receives a moderation/ban event (wstobackend.go:339) for a session that was created on a different node, already destroyed, or whose mapping was lost on restart.

Common situations: Multi-instance deployments where the ban event arrives at a node that does not own the session; banning a user right after they disconnect; stale session ids cached in admin UIs; server restart wiping the in-memory map while clients still reference old ids.

Related errors


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