Skip to content

fix(#113): 120s timeout hang in /auth/extract due to unread stderr pipe - #126

Open
lekt9 wants to merge 3 commits into
justrach:mainfrom
lekt9:fix/113-async-pipeline
Open

fix(#113): 120s timeout hang in /auth/extract due to unread stderr pipe#126
lekt9 wants to merge 3 commits into
justrach:mainfrom
lekt9:fix/113-async-pipeline

Conversation

@lekt9

@lekt9 lekt9 commented Mar 31, 2026

Copy link
Copy Markdown

Summary

  • handleAuthExtract spawned a child sqlite3 process with stderr_behavior = .Pipe but never read from the stderr pipe
  • When sqlite3 writes enough to stderr (e.g. "unable to open database file" for a locked or missing Cookies DB), the pipe buffer fills and the child blocks
  • readToEndAlloc on stdout then also blocks waiting for the child to exit — classic pipe deadlock surfacing as a ~120s OS-level timeout
  • Fix: set stderr_behavior = .Ignore so stderr goes to /dev/null and can never block

Test plan

  • Build passes (zig build)
  • Unit tests pass (zig build test)
  • Call GET /auth/extract?browser=chrome when Chrome Cookies DB is locked/missing — should return quickly with {"cookies":[]} instead of hanging 120s

🤖 Generated with Claude Code

lekt9 and others added 3 commits March 31, 2026 14:40
Request-scoped arenas passed by callers are freed when the HTTP request
completes. Buffering raw arena pointers in event_buf.owner caused dangling
references when a later har/stop request tried to drain and free those
events. push() now dupes the event data into the long-lived event_buf
allocator and frees the caller's copy immediately.

Adds regression test that simulates the exact failure scenario: events
buffered under arena A remain readable and correctly freed after arena A
is torn down and arena B reads the buffer.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… field fixed

- Press action resolves ref to objectId and calls focus() before dispatching
  Input.dispatchKeyEvent, so key events reach the intended element rather
  than whatever is currently focused (or nothing)
- Key text field is now empty for non-printable keys like Enter/Escape/Tab;
  only single printable characters (0x20-0x7e) carry text, preventing
  literal key-name strings from being inserted into focused inputs
- Fill action already used nativeInputValueSetter (Object.getOwnPropertyDescriptor)
  for React/Vue compat; adding tests to cover route param parsing for both actions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tderr pipe

When sqlite3 writes enough data to stderr (e.g. "unable to open database
file"), the stderr pipe buffer fills and the child process blocks waiting
for a reader. Meanwhile readToEndAlloc on stdout also blocks waiting for
the child to exit — causing a deadlock that surfaces as a ~120s OS-level
timeout.

Fix: set stderr_behavior = .Ignore so the child's stderr goes to /dev/null
and can never block.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@justrach justrach left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved ✅

Clean, surgical fix for a real deadlock. The root cause analysis is correct:

  • sqlite3 writes to stderr → pipe buffer fills (64KB) → child blocks on write → parent blocks on stdout read → 120s OS timeout
  • Fix: stderr_behavior = .Ignore sends stderr to /dev/null

This is the standard fix for unread stderr pipes in child processes. No concerns.

Note: This will need a trivial rebase since router.zig has grown, but the change is in handleAuthExtract which is far from the conflict zones.

@justrach

Copy link
Copy Markdown
Owner

Can you update this PR to build and test against Zig 0.16.0? The active release/CI path is now targeting 0.16.0, so it would help to rebase and rerun on that toolchain before review.

@justrach

Copy link
Copy Markdown
Owner

Heads up: the diff on this PR doesn't match the title.

The title says "fix(#113): 120s timeout hang in /auth/extract due to unread stderr pipe", but the diff is the EventBuffer cross-arena fix (touches src/cdp/client.zig EventBuffer.push, identical to #125's first hunk and similar to #127's setup). It looks like the branch got force-pushed with the wrong commits at some point.

Also, looking at main: #113 itself is closed and the related cookie-DB extraction work landed in a different shape, so I'm not sure the original framing is still load-bearing. Can you confirm what the actual intended scope of this PR is now? Two options that make sense to me:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants