Repository navigation
Conversation
A null/error/malformed eth_getBlockByNumber response surfaced as a generic "'NoneType' object is not subscriptable" warning and left the chain silently unmeasured. Now: - Validate the raw JSON-RPC response and raise BlockTimestampUnavailableError with a specific, URL-redacted diagnostic. - Retry response-level failures up to 3 times, rotating providers between attempts (transport failures already rotate inside make_request). - Track unknown lag per chain as degraded coverage: alert after 2 consecutive unmeasurable runs (--unknown-alert-after-runs), respect the cooldown, and send a "measurable again" note on recovery. Stale state is left untouched. - Add utils.formatting.redact_urls and Web3Client.rotate_provider. Closes #465 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Drop tests and an assertion whose behaviour is already covered elsewhere. Coverage of check_indexer_freshness.py is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Provider rotation logged full URLs, including the API key, and urllib3 connection errors repeat the key in a scheme-less "url: /v2/<key>" path that redact_urls did not recognise, so persistent failures forwarded it to Telegram. - Redact URLs in the shared provider logs and in ProviderConnectionError. - Stop logging invalid provider URLs, which cannot be recognised for redaction. - Teach redact_urls the urllib3 request-path form. - Report only the exception type in transport-failure alerts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #465
Problem
On 2026-11-07 14:05 UTC the freshness check logged
Failed to fetch block 47317489 timestamp on KATANA: 'NoneType' object is not subscriptable. The raweth_getBlockByNumbercall returns the JSON-RPC body as is, so anullblock or an RPC error never raises insidemake_request. Provider rotation never ran, the diagnostic said nothing useful, and Katana stayed unmeasured for that run without any notice.Changes
parse_block_timestamp): RPC error (code and message),nullresult, a non-dict body and a missing or non-hex timestamp each raiseBlockTimestampUnavailableErrorwith a specific reason.Web3Client.rotate_provider(), which does nothing when only one provider is set). Transport failures are not retried again becausemake_requesthas already gone through every provider with backoff.utils.formatting.redact_urlsreduces URLs to scheme and host and strips the scheme-lessurl: /pathin urllib3 errors. The shared provider logs andProviderConnectionErrorinutils/web3_wrapper.pynow use it, and invalid provider URLs are no longer logged. Transport-failure alerts name only the exception type, so exception text never reaches Telegram.--unknown-alert-after-runsconsecutive unmeasurable runs (default2, envINDEXER_UNKNOWN_ALERT_AFTER_RUNS), a silent Envio-channel alert goes out with the streak, the last indexed block and the reason. It uses the existing per-chain cooldown.monitoring.yamlare updated.Testing
nullresult followed by success on a retry, running out of attempts, URL redaction on transport failure, a missing client, a one-off unknown run (no alert), unknown → alert → cooldown → recovery, and an unmeasurable stale chain (no false recovery).uv run pytest: 2117 passed, 4 skipped.ruff check,ruff format --checkandty checkare clean.{"result": null}for a block it does not have.🤖 Generated with Claude Code