Frontend
Other / multiple — @ff-labs/pi-fff using @ff-labs/fff-node.
Environment
@ff-labs/pi-fff: reproduced from the 0.10.5 code path; the relevant external-finder path still appears present in 0.10.6
- Pi: 0.84.4
- Node: 26.0.0
- macOS 27.0
Reproduction
Run an external absolute-path grep against a package under an otherwise broad indexed tree:
ffgrep /allowRanges/ in ~/.pi/agent/npm/node_modules/pi-web-access/ limit 20
Intermittently, Pi remains on Working... indefinitely. The tool-level 10-second grep budget and the auxiliary finder startup timeout do not recover the process.
The target itself is small and the same search normally completes quickly, so this is not simply a slow full-tree scan.
Expected behavior
The search should return matches, No matches found, or a bounded actionable timeout without blocking Pi's main JavaScript thread.
Actual behavior
A synchronous native create/index/grep call can stop returning. Because the event loop is blocked inside FFI, an outer Promise.race/timer cannot fire and the whole Pi process remains stuck.
Investigation
Instrumentation of the pi-fff auxiliary finder lifecycle showed this sequence in the reproduced case:
- A broader auxiliary finder exceeded its scan/startup wait.
- Native scan/warmup continued after the JavaScript-side wait timed out.
- The finder remained reusable while the global creation queue was released.
- A later external-root grep entered native FFI while the earlier native work was still active.
- Once the synchronous FFI call stopped returning, the JavaScript timeout could not interrupt it.
There may also be an interaction with:
Those fixes improve routing/budget behavior, but a JavaScript timer still cannot terminate a native synchronous call that has already wedged.
Locally verified mitigation
As a local diagnostic/fix, we moved external-path grep only behind a bounded child-process lifecycle:
- exact-root workers
- same-root startup deduplication
- serialized native finder creation across roots
- bounded hot-worker pool
- startup/request/abort/shutdown all terminate the child process when necessary
- workspace grep and fffind remain unchanged
Regression coverage includes cold/hot search, matches and zero matches, explicit node_modules roots, startup timeout, grep timeout, abort, concurrent roots, and recovery after termination.
With that isolation, the original target returns 38 matches in about 1.6 seconds, and a deliberately wedged native worker can be killed without freezing Pi.
I am filing the issue first because the preferred upstream fix may be either:
- native cancellation/time-budget enforcement in the SDK/Rust owner, or
- process/thread isolation in pi-fff for external-path operations.
I can submit the isolated pi-fff implementation if that direction is useful.
Logs
No useful log is emitted once the synchronous FFI call blocks; the JavaScript process cannot progress far enough to report the timeout.
Frontend
Other / multiple —
@ff-labs/pi-fffusing@ff-labs/fff-node.Environment
@ff-labs/pi-fff: reproduced from the 0.10.5 code path; the relevant external-finder path still appears present in 0.10.6Reproduction
Run an external absolute-path grep against a package under an otherwise broad indexed tree:
Intermittently, Pi remains on
Working...indefinitely. The tool-level 10-second grep budget and the auxiliary finder startup timeout do not recover the process.The target itself is small and the same search normally completes quickly, so this is not simply a slow full-tree scan.
Expected behavior
The search should return matches,
No matches found, or a bounded actionable timeout without blocking Pi's main JavaScript thread.Actual behavior
A synchronous native create/index/grep call can stop returning. Because the event loop is blocked inside FFI, an outer
Promise.race/timer cannot fire and the whole Pi process remains stuck.Investigation
Instrumentation of the pi-fff auxiliary finder lifecycle showed this sequence in the reproduced case:
There may also be an interaction with:
node_modulessubtreeThose fixes improve routing/budget behavior, but a JavaScript timer still cannot terminate a native synchronous call that has already wedged.
Locally verified mitigation
As a local diagnostic/fix, we moved external-path grep only behind a bounded child-process lifecycle:
Regression coverage includes cold/hot search, matches and zero matches, explicit
node_modulesroots, startup timeout, grep timeout, abort, concurrent roots, and recovery after termination.With that isolation, the original target returns 38 matches in about 1.6 seconds, and a deliberately wedged native worker can be killed without freezing Pi.
I am filing the issue first because the preferred upstream fix may be either:
I can submit the isolated pi-fff implementation if that direction is useful.
Logs
No useful log is emitted once the synchronous FFI call blocks; the JavaScript process cannot progress far enough to report the timeout.