m1k1o/neko · error

ErrIsNotTheHost

ErrIsNotTheHost

Error message

is not the host

What it means

The declared sentinel ErrIsNotTheHost in server/internal/websocket/handler/control.go is returned by controlRelease when the session tries to release host control but is not the current host. Releasing control is an operation only meaningful for the session that currently owns it.

Source

Thrown at server/internal/websocket/handler/control.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"
	"github.com/m1k1o/neko/server/pkg/xorg"
)

var (
	ErrIsNotAllowedToHost = errors.New("is not allowed to host")
	ErrIsNotTheHost       = errors.New("is not the host")
	ErrIsAlreadyTheHost   = errors.New("is already the host")
	ErrIsAlreadyHosted    = errors.New("is already hosted")
)

func (h *MessageHandlerCtx) controlRelease(session types.Session) error {
	if !session.Profile().CanHost || session.PrivateModeEnabled() {
		return ErrIsNotAllowedToHost
	}

	if !session.IsHost() {
		return ErrIsNotTheHost
	}

	h.desktop.ResetKeys()
	session.ClearHost()

	return nil
}

View on GitHub (pinned to b0f01cedea)

Solutions

  1. Only send control release when the client's tracked host ID matches its own session ID.
  2. Refresh client state from host/control events (control/locked updates) before acting.
  3. Ignore this sentinel client-side and re-sync host status instead of retrying.
  4. Use control request if the goal is to obtain control rather than release it.

Example fix

// before
neko.websocket.send(event.CONTROL_RELEASE) // always on click
// after
if (neko.state.isHost) {
  neko.websocket.send(event.CONTROL_RELEASE)
}
Defensive patterns

Strategy: type-guard

Validate before calling

// client-side, before sending release
if (state.hostId !== state.sessionId) {
  console.warn('not the host: release skipped')
  return
}

Type guard

function isCurrentHost(state) {
  return state.hostId != null && state.hostId === state.sessionId
}

Try / catch

try {
  socket.emit('control/release')
} catch (e) {
  if (e.message === 'is not the host') resyncHostState() // stale UI
}

Prevention

When it happens

Trigger: Sending a control release message from a session while session.IsHost() is false — e.g. after another user took over, or when nobody hosts.

Common situations: Stale client state: the UI still thinks it is the host after another participant grabbed control; double-clicking a release button; a reconnecting client re-sending release on resume.

Related errors


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