{"record":{"id":"e4e4aac548b5e825","repo":"m1k1o/neko","slug":"session-is-already-connected","errorCode":null,"errorMessage":"session is already connected","messagePattern":"session is already connected","errorType":"error_code","errorClass":"ErrSessionAlreadyConnected","httpStatus":null,"severity":"warning","filePath":"server/pkg/types/session.go","lineNumber":12,"sourceCode":"package types\n\nimport (\n\t\"errors\"\n\t\"net/http\"\n\t\"time\"\n)\n\nvar (\n\tErrSessionNotFound         = errors.New(\"session not found\")\n\tErrSessionAlreadyExists    = errors.New(\"session already exists\")\n\tErrSessionAlreadyConnected = errors.New(\"session is already connected\")\n\tErrSessionLoginDisabled    = errors.New(\"session login disabled\")\n\tErrSessionLoginsLocked     = errors.New(\"session logins locked\")\n)\n\ntype Cursor struct {\n\tX int `json:\"x\"`\n\tY int `json:\"y\"`\n}\n\ntype SessionProfile struct {\n\tId      string\n\tToken   string\n\tProfile MemberProfile\n}\n\ntype SessionState struct {\n\tIsConnected bool `json:\"is_connected\"`\n\t// when the session was last connected","sourceCodeStart":1,"sourceCodeEnd":30,"githubUrl":"https://github.com/m1k1o/neko/blob/b0f01cedea68893e85a3fd852c0521238c285695/server/pkg/types/session.go#L1-L30","documentation":"ErrSessionAlreadyConnected is a sentinel error in the neko types package indicating that a Login/connect attempt targeted a session that already has an active (WebSocket) peer connection. The server refuses a second simultaneous connection for the same session.","triggerScenarios":"Login called for a session whose WebSocket peer is still registered as connected; a second tab/device reusing the same session while it is still marked connected.","commonSituations":"Opening the same neko room in two tabs with the same session; zombie connections where the old socket hasn't been cleaned up yet after a network drop; clients that don't send a proper disconnect before reconnecting.","solutions":["Disconnect the existing session (Disconnect(id) or client-side logout) before reconnecting.","Wait for the old connection to be cleaned up / rely on heartbeat timeout, then retry.","Use the server's merciful_reconnect setting so a reconnecting peer takes over the session.","Close the duplicate client tab/connection."],"exampleFix":"// before\n_, _, err := memberManager.Login(username, password) // fails: session already connected\n// after\nif err := sessions.Disconnect(sessionId); err != nil {\n    return err\n}\n_, _, err = memberManager.Login(username, password)","handlingStrategy":"retry","validationCode":"// check the session's connection state first\nif st := session.State(); st.IsConnected {\n    return errors.New(\"session already has an active connection\")\n}","typeGuard":null,"tryCatchPattern":"err := retry.Do(func() error {\n    _, _, err := manager.Login(username, password)\n    if errors.Is(err, types.ErrSessionAlreadyConnected) {\n        return retry.Retriable(err) // wait for cleanup, then retry\n    }\n    return err\n})","preventionTips":["Close previous connections before opening new ones.","Close duplicate tabs using the same session.","Rely on heartbeat timeouts to clean zombie connections.","Track connection state client-side to prevent double connects."],"tags":["session","websocket","concurrency","go"],"backgroundTag":"connection-already-open","analyzedSha":"b0f01cedea68893e85a3fd852c0521238c285695","analyzedAt":"2026-09-01T10:35:56.638Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}