{"record":{"id":"bcf918cc7d641473","repo":"necolas/react-native-web","slug":"touchable-cannot-transition-from-curstate-to","errorCode":null,"errorMessage":"Touchable cannot transition from `${curState}` to `${signal}` for responder `${responderID}`","messagePattern":"Touchable cannot transition from `(.+?)` to `(.+?)` for responder `(.+?)`","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/react-native-web/src/exports/Touchable/index.js","lineNumber":778,"sourceCode":"    const responderID = this.state.touchable.responderID;\n    const curState = this.state.touchable.touchState;\n    const nextState = Transitions[curState] && Transitions[curState][signal];\n    if (!responderID && signal === Signals.RESPONDER_RELEASE) {\n      return;\n    }\n    if (!nextState) {\n      throw new Error(\n        'Unrecognized signal `' +\n          signal +\n          '` or state `' +\n          curState +\n          '` for Touchable responder `' +\n          responderID +\n          '`'\n      );\n    }\n    if (nextState === States.ERROR) {\n      throw new Error(\n        'Touchable cannot transition from `' +\n          curState +\n          '` to `' +\n          signal +\n          '` for responder `' +\n          responderID +\n          '`'\n      );\n    }\n    if (curState !== nextState) {\n      this._performSideEffectsForTransition(curState, nextState, signal, e);\n      this.state.touchable.touchState = nextState;\n    }\n  },\n\n  _cancelLongPressDelayTimeout: function () {\n    this.longPressDelayTimeout && clearTimeout(this.longPressDelayTimeout);\n    this.longPressDelayTimeout = null;","sourceCodeStart":760,"sourceCodeEnd":796,"githubUrl":"https://github.com/necolas/react-native-web/blob/a9de220ba9e65bdea540fb5322ffb1da2b0bf442/packages/react-native-web/src/exports/Touchable/index.js#L760-L796","documentation":"Companion to the unrecognized-signal throw: the transition lookup succeeded but maps to States.ERROR, meaning the state machine explicitly forbids moving from curState via this signal. Touchable throws to surface the illegal transition with the responder ID. Indicates a broken responder lifecycle or library bug.","triggerScenarios":"A signal arrives that the transition table deliberately maps to ERROR for the current state — e.g. a second RESPONDER_GRANT while already active, or a termination/enter signal in a terminal state.","commonSituations":"Fuzzy/overlapping pointer events hitting the same Touchable twice; touch cancel sequences racing with release; custom long-press/press-in logic forcing state changes; known library race conditions fixed in newer versions.","solutions":["Upgrade react-native-web to pick up state-machine race fixes.","Reproduce and file an issue with the reported curState → signal pair.","Avoid calling Touchable responder internals directly from app code.","Simplify nesting of touchable/gesture components around the failing responder."],"exampleFix":"// before (app code forcing internal state)\nref._receiveSignal(Signals.ENTER_PRESS_PRESSIN, id);\n// after\n// rely on native pointer events; upgrade react-native-web instead","handlingStrategy":"try-catch","validationCode":"// Only legal transitions should ever be dispatched:\nconst nextState = Transitions[curState] && Transitions[curState][signal];\nif (nextState === States.ERROR) throw new Error(`Illegal transition ${curState} -> ${signal}`);","typeGuard":"const isLegalTransition = (state, signal) => Transitions[state]?.[signal] !== States.ERROR;","tryCatchPattern":"try { pressHandlers(); } catch (e) { if (/cannot transition from/.test(e.message)) reportStateRace(e.message); else throw e; }","preventionTips":["Don't drive responder state changes manually","Debounce/dedupe pointer events that can hit the same Touchable twice","Check the react-native-web changelog for Touchable race fixes before debugging app code"],"tags":["react-native-web","touchable","state-machine","invariant"],"backgroundTag":"invalid-state-transition","analyzedSha":"a9de220ba9e65bdea540fb5322ffb1da2b0bf442","analyzedAt":"2026-09-01T10:01:09.883Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}