Troubleshooting Guide
Common issues and solutions when working with Tombatron.Turbo.
Turbo Frames Issues
Frame Not Updating
Symptom: Clicking a link inside a frame loads the full page instead of updating just the frame.
Solutions:
-
Check that Turbo.js is loaded:
<script type="module" src="https://cdn.jsdelivr.net/npm/@hotwired/turbo@8/dist/turbo.es2017-esm.min.js"></script> -
Verify the response contains a matching frame:
<!-- Response must include a frame with the same ID -->
<turbo-frame id="cart-items">
<!-- Updated content -->
</turbo-frame> -
Check your handler returns a partial:
if (HttpContext.IsTurboFrameRequest())
{
return Partial("_MyPartial", Model);
} -
Verify the partial includes the turbo-frame element:
<!-- _MyPartial.cshtml -->
<turbo-frame id="cart-items">
@* Content must be wrapped in the frame *@
</turbo-frame>
Full Page Returned Instead of Frame Content
Symptom: Request works but returns entire page HTML.
Solutions:
-
Check for the Turbo-Frame header:
// Check the header directly
if (Request.Headers.ContainsKey("Turbo-Frame"))
// Or use the extension method
if (HttpContext.IsTurboFrameRequest()) -
Ensure middleware is configured:
app.UseTurbo(); // Must be called -
Check the request in browser DevTools:
- Open Network tab
- Click the link
- Look for
Turbo-Frameheader in request headers
Frame Shows "Content Missing"
Symptom: Frame displays error about missing content.
Solution: Ensure the response contains a <turbo-frame> with a matching ID. The frame ID in the response must exactly match the requesting frame's ID.
Caching Issues
Symptom: Stale content appears or wrong content is served.
Solutions:
-
Verify Vary header is enabled:
options.AddVaryHeader = true; // Default -
Check CDN configuration: Ensure your CDN respects the
Vary: Turbo-Frameheader. -
Clear browser cache when testing.
Turbo Streams Issues
Not Receiving Updates
Symptom: Server sends updates but client doesn't receive them.
Solutions:
-
Check SignalR connection:
window.addEventListener('turbo-signalr:connected', () => {
console.log('Connected');
}); -
Verify hub is mapped:
app.MapTurboHub(); // Required -
Check stream name matches:
<!-- Client -->
<turbo-stream-source-signalr stream="notifications">// Server - must match exactly
await _turbo.Stream("notifications", ...); -
Check browser console for errors
SignalR Connection Fails
Symptom: SignalR won't connect.
Solutions:
-
Check SignalR is loaded:
<script src="https://cdn.jsdelivr.net/npm/@microsoft/signalr@8/dist/browser/signalr.min.js"></script> -
Verify hub URL:
<turbo-stream-source-signalr hub-url="/turbo-hub">// Must match the configured path
options.HubPath = "/turbo-hub"; -
Check for CORS issues if hub is on a different origin.
-
Check server logs for connection errors.
Subscription Denied
Symptom: Client connects but subscription fails.
Solutions:
-
If using signed stream names:
- Ensure the stream name in the HTML matches what the server signed
- Check token hasn't expired
- Verify Data Protection is configured
-
If using custom authorization:
- Check your
ITurboStreamAuthorizationimplementation - Verify the user context is available
- Check your
Updates Applied to Wrong Element
Symptom: DOM updates target incorrect elements.
Solution: Ensure target IDs are unique across the page:
// Target must be a unique ID
builder.Update("cart-total", ...); // ID: cart-total
Form Issues
Form Submission Not Working
Symptom: Forms don't submit or page reloads fully.
Solutions:
-
For Turbo Frame forms, ensure the response contains a matching frame.
-
For Turbo Stream forms, return the correct content type:
if (Request.Headers.Accept.ToString().Contains("text/vnd.turbo-stream.html"))
{
return Content(streamHtml, "text/vnd.turbo-stream.html");
} -
Check anti-forgery tokens are included if required.
400 Bad Request on POST
Symptom: POST requests return 400 error.
Solutions:
-
Anti-forgery token missing:
<form method="post">
@Html.AntiForgeryToken()
...
</form> -
Or disable for the page:
[IgnoreAntiforgeryToken]
public class MyPageModel : PageModel
Performance Issues
Slow Initial Load
Solutions:
-
Use lazy loading for below-the-fold frames:
<turbo-frame id="comments" src="..." loading="lazy"> -
Reduce the number of streams subscribed to initially.
High Memory Usage
Solutions:
-
Limit active subscriptions - unsubscribe from streams when not needed.
-
Check for memory leaks in custom event handlers.
Debugging Tips
Enable Detailed Logging
builder.Logging.AddFilter("Tombatron.Turbo", LogLevel.Debug);
builder.Logging.AddFilter("Microsoft.AspNetCore.SignalR", LogLevel.Debug);
Check Request Headers
Use browser DevTools to inspect:
Turbo-Frameheader on frame requestsAcceptheader for stream requests
Monitor SignalR Traffic
In browser DevTools:
- Go to Network tab
- Filter by "WS" for WebSocket
- Click on the SignalR connection
- View Messages tab to see traffic
Test Without Turbo
Temporarily disable Turbo to verify server-side logic:
<meta name="turbo-visit-control" content="reload">
Common Error Messages
"Frame not found"
The response didn't contain a <turbo-frame> with the expected ID.
"Content missing from response"
Same as above - ensure your partial includes the frame element.
"Subscription failed"
Authorization denied the stream subscription. Check authorization logic and user context.
"Connection refused"
SignalR hub isn't reachable. Verify MapTurboHub() is called and the URL is correct.
Getting Help
If you're still stuck:
- Check the GitHub Issues
- Create a minimal reproduction case
- Include relevant logs and configuration