{"record":{"id":"184bf58c324cc159","repo":"m1k1o/neko","slug":"unknown-touch-id-v","errorCode":null,"errorMessage":"unknown touch id %v","messagePattern":"unknown touch id (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"server/pkg/xinput/xinput.go","lineNumber":87,"sourceCode":"\td.debounceTouchIds[touchId] = time.Now()\n\n\tmsg := Message{\n\t\t_type:    XI_TouchBegin,\n\t\ttouchId:  touchId,\n\t\tx:        int32(x),\n\t\ty:        int32(y),\n\t\tpressure: pressure,\n\t}\n\t_, err := d.conn.Write(msg.Pack())\n\treturn err\n}\n\nfunc (d *driver) TouchUpdate(touchId uint32, x, y int, pressure uint8) error {\n\td.mu.Lock()\n\tdefer d.mu.Unlock()\n\n\tif _, ok := d.debounceTouchIds[touchId]; !ok {\n\t\treturn fmt.Errorf(\"unknown touch id %v\", touchId)\n\t}\n\n\td.debounceTouchIds[touchId] = time.Now()\n\n\tmsg := Message{\n\t\t_type:    XI_TouchUpdate,\n\t\ttouchId:  touchId,\n\t\tx:        int32(x),\n\t\ty:        int32(y),\n\t\tpressure: pressure,\n\t}\n\t_, err := d.conn.Write(msg.Pack())\n\treturn err\n}\n\nfunc (d *driver) TouchEnd(touchId uint32, x, y int, pressure uint8) error {\n\td.mu.Lock()\n\tdefer d.mu.Unlock()","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/m1k1o/neko/blob/b0f01cedea68893e85a3fd852c0521238c285695/server/pkg/xinput/xinput.go#L69-L105","documentation":"TouchUpdate is called to send an XI_TouchUpdate event for an in-progress touch gesture. The driver tracks active touch IDs in debounceTouchIds (populated by TouchBegin); if the given touchId is not present there, it means no touch with that ID was begun, so the driver refuses to synthesize an update and returns this error. It is a state-machine guard against orphan touch updates.","triggerScenarios":"Calling TouchUpdate(touchId, x, y, pressure) with a touchId that was never registered via TouchBegin, or after the touch was already finished with TouchEnd (which deletes the ID), or after an internal debounce cleanup removed the ID.","commonSituations":"Client reconnects mid-gesture and resumes sending TouchUpdate for a touch the server never saw; a lost/undelivered TouchBegin due to network issues; double-sending TouchEnd then continuing updates; race where two clients drive the same touch sequence.","solutions":["Ensure TouchBegin is called and succeeds for each touchId before any TouchUpdate for that ID","Track touch lifecycle client-side; on 'unknown touch id' fall back to sending TouchBegin again to re-register the touch","Stop sending updates for a touch after TouchEnd; generate a new touchId for the next gesture","Check for duplicate/parallel input clients reusing the same touch IDs"],"exampleFix":"// before\nif err := xinput.TouchUpdate(id, x, y, p); err != nil { log.Fatal(err) }\n// after\nif err := xinput.TouchUpdate(id, x, y, p); err != nil {\n    // re-register the touch then retry\n    if beginErr := xinput.TouchBegin(id, x, y, p); beginErr == nil {\n        _ = xinput.TouchUpdate(id, x, y, p)\n    }\n}","handlingStrategy":"try-catch","validationCode":"// caller-side touch state\nvar activeTouches = map[uint32]bool{}\nfunc canUpdate(id uint32) bool { return activeTouches[id] }","typeGuard":"func isUnknownTouchID(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"unknown touch id\")\n}","tryCatchPattern":"if err := d.TouchUpdate(id, x, y, p); err != nil {\n    if isUnknownTouchID(err) {\n        // re-begin then retry, or drop the stale touch\n        _ = d.TouchBegin(id, x, y, p)\n        err = d.TouchUpdate(id, x, y, p)\n    }\n    if err != nil { return err }\n}","preventionTips":["Always call TouchBegin before TouchUpdate for a given ID","Generate unique touchIds per gesture; never reuse after TouchEnd","Treat reconnects as gesture abort: reset local touch state","Keep a local mirror of active touch IDs and check it before each call"],"tags":["input","touch","state-machine","x11"],"backgroundTag":"unknown-touch-id","analyzedSha":"b0f01cedea68893e85a3fd852c0521238c285695","analyzedAt":"2026-09-01T10:35:56.638Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}