{"record":{"id":"50fb0da067b5fcc6","repo":"m1k1o/neko","slug":"errisnotthehost","errorCode":"ErrIsNotTheHost","errorMessage":"is not the host","messagePattern":"is not the host","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/internal/websocket/handler/control.go","lineNumber":14,"sourceCode":"package handler\n\nimport (\n\t\"errors\"\n\n\t\"github.com/m1k1o/neko/server/pkg/types\"\n\t\"github.com/m1k1o/neko/server/pkg/types/event\"\n\t\"github.com/m1k1o/neko/server/pkg/types/message\"\n\t\"github.com/m1k1o/neko/server/pkg/xorg\"\n)\n\nvar (\n\tErrIsNotAllowedToHost = errors.New(\"is not allowed to host\")\n\tErrIsNotTheHost       = errors.New(\"is not the host\")\n\tErrIsAlreadyTheHost   = errors.New(\"is already the host\")\n\tErrIsAlreadyHosted    = errors.New(\"is already hosted\")\n)\n\nfunc (h *MessageHandlerCtx) controlRelease(session types.Session) error {\n\tif !session.Profile().CanHost || session.PrivateModeEnabled() {\n\t\treturn ErrIsNotAllowedToHost\n\t}\n\n\tif !session.IsHost() {\n\t\treturn ErrIsNotTheHost\n\t}\n\n\th.desktop.ResetKeys()\n\tsession.ClearHost()\n\n\treturn nil\n}","sourceCodeStart":1,"sourceCodeEnd":32,"githubUrl":"https://github.com/m1k1o/neko/blob/b0f01cedea68893e85a3fd852c0521238c285695/server/internal/websocket/handler/control.go#L1-L32","documentation":"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.","triggerScenarios":"Sending a control release message from a session while session.IsHost() is false — e.g. after another user took over, or when nobody hosts.","commonSituations":"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.","solutions":["Only send control release when the client's tracked host ID matches its own session ID.","Refresh client state from host/control events (control/locked updates) before acting.","Ignore this sentinel client-side and re-sync host status instead of retrying.","Use control request if the goal is to obtain control rather than release it."],"exampleFix":"// before\nneko.websocket.send(event.CONTROL_RELEASE) // always on click\n// after\nif (neko.state.isHost) {\n  neko.websocket.send(event.CONTROL_RELEASE)\n}","handlingStrategy":"type-guard","validationCode":"// client-side, before sending release\nif (state.hostId !== state.sessionId) {\n  console.warn('not the host: release skipped')\n  return\n}","typeGuard":"function isCurrentHost(state) {\n  return state.hostId != null && state.hostId === state.sessionId\n}","tryCatchPattern":"try {\n  socket.emit('control/release')\n} catch (e) {\n  if (e.message === 'is not the host') resyncHostState() // stale UI\n}","preventionTips":["Keep client host state synchronized from server control/host events.","Clear 'is host' UI state as soon as another session takes control.","Ignore (don't retry) this sentinel — it indicates stale state, not a transient fault.","After reconnect, re-query host status before sending control commands."],"tags":["websocket","host-control","state-sync"],"backgroundTag":"not-the-host","analyzedSha":"b0f01cedea68893e85a3fd852c0521238c285695","analyzedAt":"2026-09-01T10:35:56.638Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}