Skip to content

Say why a page never loaded instead of calling every failure a timeout - #17

Merged
jehrr merged 1 commit into
mainfrom
fix/canary-load-error-2026-10-20
Oct 20, 2026
Merged

jehrr merged 1 commit into
mainfrom
fix/canary-load-error-2026-10-20

Conversation

@jehrr

@jehrr jehrr commented Oct 20, 2026

Copy link
Copy Markdown
Collaborator

Problem

In canary run 39479200544 (2026-10-20), the question run through QUORA_PROXY passed: 262 rows, complete. The topic run in the same job then exited 5. The log shows:

18:59:36,315 Fetching page 1/1: https://www.quora.com/topic/Machine-Learning
18:59:36,379 Timeout loading https://www.quora.com/topic/Machine-Learning (attempt 1/4) — retrying in 30.0s.

The first failure came 64 ms after the navigation started. The navigation timeout is 60 s, so this was not a timeout. The three retries also failed straight away; the gaps between them were the 30/60/120 s backoff. Playwright's goto raised a PWError that is not a proxy error the engine recognises. The engine logged it as "Timeout" and dropped the message. The sidecar said page_load_timeout and nothing more, so this run's failure cannot be diagnosed after the fact. Selenium and pyppeteer printed str(e)[:120] without masking credentials.

Change (all three engines)

  • A failed navigation is logged as Timeout loading only when the driver raised its timeout type. Any other error is logged as Navigation failed loading. Both lines include the error's first line, with proxy credentials masked by the engine's existing _mask_credentials.
  • The final Gave up loading ... after N attempt(s): <reason> line names the reason too.
  • The reason is stored on PageOutcome.load_error. The sidecar gains load_error: the reason for the first page that never loaded, or null.
  • Exit codes and stop_reason are unchanged.

Evidence

  • New driven smoke checks, one set per engine. A stubbed session whose navigation always raises (1) a non-timeout driver error with a credential in its text and (2) the driver's timeout type. For each case the checks require load_failed, load_error equal to the masked first line, the right label, the reason in both the retry and the give-up line, no credential in the log or the outcome, and no solve bought. A source check covers the sidecar key in each engine.
  • smoke_test.py: OK in a core-only venv (driving skipped). Also OK in separate playwright, selenium and pyppeteer venvs (pip only, no browser download), with each engine's driven checks shown as PASS.
  • Controls, run in the playwright venv:
    • Forcing the label back to an unconditional "Timeout" turns "Error is logged as 'Navigation failed loading'" red.
    • Removing outcome.load_error = load_error turns both "... -> load_failed with the reason on the outcome" checks red.
    • With both restored, the suite is OK.
  • .github/ci_checks.py --all: ok.

What this does not establish

This PR does not say why the topic navigation failed on 2026-10-20. That error text was discarded. The next canary run will record it in the log and in canary_topic.meta.json.

🤖 Generated with Claude Code

https://claude.ai/code/session_01CKsd7q25N19WzUZjrAdzx8

Playwright logged any navigation error as "Timeout loading" with no
reason; the 2026-10-20 topic canary failed four times within 64 ms of
starting the navigation and left nothing to diagnose. All three engines
now log the error's first line (credentials masked), call it a timeout
only when it is one, and record it as load_error in the sidecar.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CKsd7q25N19WzUZjrAdzx8
@jehrr
jehrr force-pushed the fix/canary-load-error-2026-10-20 branch from 2094b0d to fb5bb5f Compare October 20, 2026 19:32
@jehrr
jehrr merged commit bc31707 into main Oct 20, 2026
7 checks passed
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.

1 participant