Always provide a retry handler, fix cold-boot retries, and expand logging#247
Merged
Conversation
Log the resolve request, its outcome (no redirect, same-origin, or cross-origin), and—crucially—the error details in the catch blocks of Session.resolveRedirect which were previously silent.
ColdBootVisit silently swallowed the status code when canceling non-2xx responses. Now logs at warning level with the status code and URL so errors like 404s are visible in the log files.
* main: (55 commits) Set `lazyLoadTabs` to `true` by default. Split HotwireLogger into focused files under Logging/ Move and expand custom logger tests Remove obsolete logger. Enable debug logging automatically for debug builds in the Demo app. Remove obsolete `Logging` in favor of `HotwireLogger`. Allow injection of a custom logger Make redirect-resolution timeout configurable Add ScriptMessage.isReady accessor Consolidate Turbo.js status codes into a TurboError type. Use `HotwireNativeError` instead of `Error`. Fix refresh_historical_location restoring from snapshot cache Cancel leaked WKWebView navigations in test simulator Move default logger to config variable Remove Hotwire.config.debugLoggingEnabled Rename logDestination: LogDestination to logger: HotwireLogger Remove explicit type Log destination Add configuration to lazy load tabs Make HotwireTab.image optional to mimic UITab API ...
- Correct the web-view-recreation skip log: it fires when the process is not terminated, not when a topmost visitable is missing - Fix typo and clarify the no-parent reload skip message - Drop a stray whitespace-only line
svara
force-pushed
the
zoe/error0fix+logging-retryable+extralogs
branch
from
June 30, 2026 12:04
c1f53ca to
5b59e68
Compare
Covers the new Navigator behavior: a retry handler is always provided (even for previously non-retryable errors), the handler retries the visit directly with a cold boot when there is no topmost visitable, and falls back to reloading the session otherwise.
svara
marked this pull request as ready for review
June 30, 2026 12:09
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.
Summary
Reworks failed-visit retry handling and adds diagnostic logging across the navigation/session flow. Three themes:
1. Retry handling
Navigator.session(_:didFailRequestForVisitable:)no longer gates the handler onerror.isRetryable— every failed visit now gets a retry action, letting the app/user decide.session.topmostVisitable == nil,session.reload()is a no-op, so the old Retry button did nothing. The handler now falls back tosession.visit(visitable, reload: true)to force a cold boot.isRetryablefromHTTPErrorandHotwireNativeError(and their tests). This API was introduced after the last release, so its removal is not a breaking change for shipped consumers.2.
RedirectHandler→JSFetchRecoveryHandlerRedirectHandlerError→JSFetchRecoveryError) to reflect that it recovers failed Turbo.js fetches, not just redirects. No behavioral change.3. Logging
info/debuglogging acrossNavigatorrouting/session inspection,Session.reload/resolveRedirect,ColdBootVisit(now logs the HTTP status on failure), andVisitableViewControllerlocation-state resolution.WebViewPolicyManager's "no handler for navigation action" fromwarningtoinfo(it falls through to.allow).Because the retry handler is now always non-nil and the default
ErrorPresentershows a Retry button iffretryHandler != nil, all error types now display a Retry button — including404/401/403, offline, and timeout, which previously suppressed it. This is intentional, but worth calling out for release notes.Testing
isRetryableunit tests (property no longer exists); updatedJSFetchRecoveryHandlerTestsfor the rename.NavigatorRetryHandlerTestscovering the new behavior: the handler is always provided (even for a previously non-retryable 404), retries the visit directly with a cold boot when there is no topmost visitable, and reloads the session otherwise.