Store the return value from setTimeout in id, but also check where debounce is created because rebuilding it on every input event resets the closure and makes a correct implementation still look broken.
The missing id = setTimeout(...) is the bug, but the sneakier failure mode is passing a pooled event object into the delayed callback in some UI libs, so grab e.target.value synchronously first.