DEV Community

Deva
Deva

Posted on

I Broke My SPA Fallback by Renaming a FastAPI Parameter to Satisfy a Linter

The dashboard SPA fallback was returning 422 on every route that was not an API route. FastAPI kept asking for full_path as a query param. The handler declared _full_path. Same thing, I assumed. Not the same thing.

FastAPI's path parameter injection requires the function parameter name to match the path template exactly. My route was /{full_path:path} and the handler had _full_path. Python treats those as different identifiers. FastAPI tried to inject full_path from the path, found no matching parameter, fell back to looking for it as a query string, found nothing, and returned 422. Every React route except / was dead.

The fix is one character: rename _full_path to full_path.

Why was it _full_path in the first place? I had run the linter and my editor suggested prefixing unused parameters with underscores. The parameter was "unused" in the sense that the handler ignores its value and returns index.html regardless of what path comes in. The linter was technically correct and practically wrong. I applied the suggestion without thinking about whether FastAPI cared about the name.

The second bug was a port conflict. The server was on 8765, which outreach_ui.py had already claimed. On a cold boot both processes race. The dashboard started second, failed to bind, failed silently, and I spent time wondering why the frontend was dead before checking what was actually listening on 8765.

The fix: move to 8766. One digit. No more race.

What I would do differently

Keep a port registry. There is no file in this monorepo that lists which process owns which port. It is a monorepo with several engines and several UIs and I am already on 8766 after colliding with 8765. Both ports were picked incrementally under the assumption that I would remember. I did not remember. A single ports.md or even a comment block at the top of each server entry point would have made this a five second check instead of a debugging session.

On the FastAPI issue: stop applying linter suggestions at framework boundaries without reading the framework contract. The underscore convention for unused parameters is sensible in normal Python. Route handlers are not normal Python. When FastAPI injects path params by name, "unused from Python's perspective" is completely different from "unused from FastAPI's perspective." The right move is a # noqa comment or a type annotation that satisfies the linter, not a rename that silently severs injection. The linter saw a smell that was not a smell. I trusted it anyway.

Neither fix was clever. The dashboard works now. Every SPA route hands off to index.html, React Router takes it from there, and nothing is fighting over port 8765 anymore. Two bugs, two single line fixes, one pattern: automation told me something was wrong and I acted without reading the local contract first. Worth noticing.

Top comments (0)