Skip to content

Watcher timing issue: debounce never triggers and step fires once based on first modification #360

@mijolabs

Description

@mijolabs

Description

The debounce and step parameters for the watcher generator appear to be malfunctioning on my system, or I might be misunderstanding their intended behavior.

According to the API docs:

Name Type Description Default
debounce int maximum time in milliseconds to group changes over before yielding them. 1600
step int time to wait for new changes in milliseconds, if no changes are detected in this time, and at least one change has been detected, the changes are yielded. 50

My interpretation is that once a modification is detected, the watcher should wait for a full quiet period equal to step before yielding. If such a quiet period never occurs, the debounce interval should act as a maximum latency cap, causing the accumulated changes to be yielded regardless of ongoing activity. In other words, continuously modifying a file should cause the step timer to reset indefinitely, and only the expiration of debounce should trigger a yield.

However, what I am observing is the opposite:

  • debounce never appears to trigger a yield.
  • step yields a single set[tuple] event exactly once, after the configured number of milliseconds from the first modification, even if the file continues to be modified repeatedly within that interval.

Below is the code used for testing:

import watchfiles

for changes in watchfiles.watch(
    "testfile.txt",
    debounce=2_000,
    step=4_000,
    debug=True,
):
    print("Yielding:", changes)

I start this with:

uv run --with watchfiles teststep.py

In a separate terminal window, I engage in the highly sophisticated testing approach of repeatedly issuing:

echo "test" >> testfile.txt

The watcher’s debug logs show that each write is detected in real time, but no events are yielded until step milliseconds have elapsed from the initial modification. Continuous writes do not reset the step timer.

The behavior is identical when using watch, awatch, or force_polling=True.

Example Code

Watchfiles Output

# uv run watchfiles 'echo reloaded' . --verbose

[22:19:09] watchfiles v1.1.1 👀  path="/current/path" target="echo reloaded" (command) filter=DefaultFilter...
[22:19:09] running "echo reloaded" as command
[22:19:09] registering handler for SIGTERM on watchfiles process 7214
watcher: FsEventWatcher { paths: 0x1027ae360, since_when: 18446744073709551615, latency: 0.0, flags: 18, event_handler: Pointer { addr: 0x1027ae330, metadata: DynMetadata(0x103a2cdb0) }, runloop: Some((0x887358c00, JoinHandle { .. })), recursive_info: {"/current/path": true} }
reloaded
[22:19:14] rust notify timeout, continuing
[22:19:19] rust notify timeout, continuing
[22:19:24] rust notify timeout, continuing
[22:19:29] rust notify timeout, continuing
[22:19:34] rust notify timeout, continuing
[22:19:39] rust notify timeout, continuing
[22:19:44] rust notify timeout, continuing
[22:19:49] rust notify timeout, continuing
[22:19:54] rust notify timeout, continuing
[22:19:59] rust notify timeout, continuing
[22:20:05] rust notify timeout, continuing
[22:20:10] rust notify timeout, continuing
[22:20:15] rust notify timeout, continuing
[22:20:20] rust notify timeout, continuing
[22:20:25] rust notify timeout, continuing
[22:20:30] rust notify timeout, continuing
[22:20:35] rust notify timeout, continuing
^C[22:20:38] KeyboardInterrupt caught, stopping watch
[22:20:38] process already dead, exit code: 0

Operating System & Architecture

macOS-26.2-arm64-arm-64bit-Mach-O
Darwin Kernel Version 25.2.0: Tue Nov 18 21:09:40 PST 2025; root:xnu-12377.61.12~1/RELEASE_ARM64_T6000

Environment

uv-managed Python installation

Python & Watchfiles Version

python: 3.14.0 (main, Oct 31 2025, 23:20:55) [Clang 21.1.4 ], watchfiles: 1.1.1

Rust & Cargo Version

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions