{"record":{"id":"15bbff3a7045bd50","repo":"vuetifyjs/vuetify","slug":"no-samples-for-touch-id-id","errorCode":null,"errorMessage":"No samples for touch id ${id}","messagePattern":"No samples for touch id (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/vuetify/src/composables/touch.ts","lineNumber":77,"sourceCode":"\n  function addMovement (e: TouchEvent) {\n    Array.from(e.changedTouches).forEach(touch => {\n      const samples = touches[touch.identifier] ?? (touches[touch.identifier] = new CircularBuffer(HISTORY))\n      samples.push([e.timeStamp, touch])\n    })\n  }\n\n  function endTouch (e: TouchEvent) {\n    Array.from(e.changedTouches).forEach(touch => {\n      delete touches[touch.identifier]\n    })\n  }\n\n  function getVelocity (id: number) {\n    const samples = touches[id]?.values().reverse()\n\n    if (!samples) {\n      throw new Error(`No samples for touch id ${id}`)\n    }\n\n    const newest = samples[0]\n    const x: Sample[] = []\n    const y: Sample[] = []\n    for (const val of samples) {\n      if (newest[0] - val[0] > HORIZON) break\n\n      x.push({ t: val[0], d: val[1].clientX })\n      y.push({ t: val[0], d: val[1].clientY })\n    }\n\n    return {\n      x: calculateImpulseVelocity(x),\n      y: calculateImpulseVelocity(y),\n      get direction () {\n        const { x, y } = this\n        const [absX, absY] = [Math.abs(x), Math.abs(y)]","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/vuetifyjs/vuetify/blob/8d153908dffb7592eb389ddbfbab955a0ccc977f/packages/vuetify/src/composables/touch.ts#L59-L95","documentation":"getVelocity(id) reads position samples for a touch identifier from a CircularBuffer keyed by touch.identifier. It throws when touches[id] is undefined, meaning no samples were ever recorded for that id (its touchstart was not captured) or endTouch already deleted the entry.","triggerScenarios":"A touchmove/touchend fires for an identifier whose touchstart the directive never observed; calling getVelocity() manually for an id that has no buffer; endTouch cleared the entry before getVelocity ran; element mounted or v-touch bound during an in-progress gesture.","commonSituations":"Conditionally rendering (v-if) a v-touch element mid-gesture; SSR hydration timing where the directive binds after the browser dispatches touchstart; a stray touchend arriving from a different target; mixing pointer events and touch events.","solutions":["Ensure the touch-tracking element is mounted before a gesture can begin (do not toggle it with v-if during touch).","If you call getVelocity yourself, guard with the existence of touches[id] first.","Keep pointer-event and touch-event tracking consistent; do not bind/unbind mid-gesture."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// If you invoke getVelocity directly, check the sample buffer first.\nconst samples = touches[id]?.values().reverse()\nif (!samples || samples.length === 0) {\n  // no data: return zero velocity instead of throwing\n  return { x: 0, y: 0 }\n}","typeGuard":"export function hasTouchSamples (touches: Record<number, unknown>, id: number): boolean {\n  return touches[id] != null\n}","tryCatchPattern":"try {\n  const v = getVelocity(id)\n} catch (e) {\n  // touch id had no recorded samples; ignore stale/stray event\n  return { x: 0, y: 0 }\n}","preventionTips":["Mount v-touch elements before a gesture starts; avoid v-if toggling during touch.","Guard getVelocity callers against missing sample buffers.","Keep pointer and touch event tracking consistent."],"tags":["touch","gesture","internal","timing"],"backgroundTag":null,"analyzedSha":"8d153908dffb7592eb389ddbfbab955a0ccc977f","analyzedAt":"2026-08-12T21:54:20.596Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}