Skip to content

fix(claw-server): give the Sentry client a transport so run failures are sent - #2907

Merged
Nikhil (shadowfax92) merged 3 commits into
mainfrom
fix/claw-sentry-transport
Oct 13, 2026
Merged

Nikhil (shadowfax92) merged 3 commits into
mainfrom
fix/claw-sentry-transport

Conversation

@shadowfax92

Copy link
Copy Markdown
Contributor

Summary

Released BrowserOS neo servers have the Sentry DSN compiled in, but the client was built without a transport, so it never sent anything. The release workflow was passing the secret correctly; the bug is in SentrySink::new.

 RunFailureReporter::from_env
   dsn = CLAW_SENTRY_DSN at runtime, else the compiled-in DSN
   SentrySink::new(dsn)
-    Client::from_config(options)       # transport: None
-    client.is_enabled() == false   ->  None
-  fall back to FileSink, log "no Sentry DSN configured"
+    Client::from_config(options)       # transport: DefaultTransportFactory
+    client.is_enabled() == true    ->  SentrySink
+  failed `run`  ->  POST /api/<project>/envelope/

Only sentry::init / apply_defaults installs the default transport. The factory is set explicitly instead of calling apply_defaults, which would also read ambient env (SENTRY_DSN, proxies, SSL_VERIFY) and attach integrations this module avoids. A DSN that still yields no client now logs a warning rather than reading as the routine "no DSN" case.

Evidence

  • Before: the new test fails on main, and the shipped 0.0.69 binary (DSN embedded) writes ~/.browserclaw/logs/run-failures.log.* every day instead of sending.

    test services::run_failures::sentry_sink_tests::a_configured_dsn_puts_an_envelope_on_the_wire ... FAILED
    Error: a valid DSN must yield a client that can send
    

    After: the envelope reaches a local stand-in for the ingest endpoint.

    test services::run_failures::sentry_sink_tests::a_configured_dsn_puts_an_envelope_on_the_wire ... ok
    test result: ok. 13 passed; 0 failed   (cargo test -p claw-server --lib run_failures)
    
  • End to end (throwaway probe, not committed): a failing run through the real AppState wiring with CLAW_SENTRY_DSN set.
    Before: no request; run-failures.log.2026-10-13 written instead.
    After: POST /api/1/envelope/ carrying only the redacted payload:

    "message":"run failed: unrecognized:Error"
    "tags":{"duration_bucket":"instant","error_label":"unrecognized:Error"}
    "extra":{"script_fingerprint":"throw new Error(<str>);"}
    
  • TLS: the same client options reach Sentry's real ingest host over HTTPS (bogus key, rejected by Sentry as expected).

  • Full cargo test --package claw-server --locked, cargo fmt --check and cargo clippy --all-targets -- -D warnings pass.

Merge Danger

Door: two-way. Reverting restores the local-log fallback.

Blast Radius:

  • Servers built with a DSN start making outbound HTTPS requests to Sentry for the first time. Only failed run calls are sent, only with analytics consent, capped at 10 per install per day, so Sentry quota starts being used.
  • Creating the client now builds a reqwest client and starts a background transport thread at server startup; the sentry crate panics there if no TLS backend is available. It builds with the locked rustls/ring set.
  • Builds without a DSN are unchanged and keep writing run-failures.log.
  • Reaches users only with the next BrowserOS neo server release; 0.0.71 and earlier stay silent.

🤖 Generated with Claude Code

…are sent

SentrySink built its client with `sentry::Client::from_config` and bare
default options. Only `sentry::init` / `apply_defaults` installs the HTTP
transport, so the client held a valid DSN, reported itself disabled, and
`SentrySink::new` returned `None` for every build. Released servers with
the DSN compiled in therefore fell back to the local `run-failures.log`
and the neo-server Sentry project never received an event.

Set the transport factory explicitly rather than calling `apply_defaults`,
which would also read ambient env (`SENTRY_DSN`, proxies, `SSL_VERIFY`) and
attach integrations that this module deliberately avoids.

A DSN that still yields no client now logs a warning instead of reading as
the routine "no DSN" case, and a regression test asserts that an envelope
reaches a local stand-in for the ingest endpoint.
@github-actions github-actions Bot added the fix label Oct 13, 2026
@greptile-apps

greptile-apps Bot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 4/5

[Medium impact] Adds error reporting transport to Sentry client.

The PR appears safe to merge, with a non-blocking improvement needed to make the new test reliable.

Findings

  1. P2 Partial reads fail the test ▶
Fix with agent prompt
### Issue 1
packages/browseros-agent/apps/claw-server/src/services/run_failures.rs:502-508
`fake_ingest` treats one `TcpStream::read` as a complete request line. TCP can return only part of that line, so the new test can fail even when Sentry sends correctly. Read through the first newline, with a timeout, before comparing the request line.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

Adds Sentry's default transport so configured clients can send failed run reports.

  • Configured Sentry clients can now send run-failure events.

Reviews (1) · Last reviewed commit: "fix(claw-server): give the Sentry client..." · Reviewed by Greptile

Comment thread packages/browseros-agent/apps/claw-server/src/services/run_failures.rs Outdated
@github-actions

github-actions Bot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

✅ Tests passed: 1081/1081

Ran 3 of 16 suites (13 not affected by this change).

Suite Passed Failed Skipped
⏩ server-agent n/a n/a not affected
⏩ server-api n/a n/a not affected
⏩ server-tools n/a n/a not affected
⏩ server-browser n/a n/a not affected
⏩ server-integration n/a n/a not affected
⏩ server-lib n/a n/a not affected
⏩ server-root n/a n/a not affected
⏩ agent n/a n/a not affected
⏩ claw-app n/a n/a not affected
⏩ claw-onboard n/a n/a not affected
⏩ app-onboard n/a n/a not affected
⏩ build n/a n/a not affected
⏩ release n/a n/a not affected
✅ claw-server 929/929 0 0
✅ claw-server-quality passed 0 0
✅ claw-mcp 152/152 0 0

passed = ran successfully but emits no JUnit counts (a lint/format gate).

View workflow run

A single TcpStream::read may return only part of the request line, which
would fail the assertion even when the envelope was sent correctly. Read
through the first newline with a read timeout instead.
@shadowfax92
Nikhil (shadowfax92) merged commit c5cc725 into main Oct 13, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant