Got a bug report: "Renaming a project returns 405 Method Not Allowed" on a self-built dashboard. The cause was simple, but it's a classic gotcha when maintaining SPAs long-term, so I'm documenting it.
Symptoms
On the project list page, inline-editing a project name and saving triggers POST /api/simple-tasks/rename 405 (METHOD NOT ALLOWED) in the browser console. Flask's server log showed the same 405.
Root Cause: Frontend-Backend Route Mismatch
Flask had /api/update-project-name registered in a different context, but the frontend JavaScript was calling /api/simple-tasks/rename.
In other words:
- The frontend (SPA) was written to use a new API path
- The backend (Flask) never got the corresponding route added
Flask returns 405 because it doesn't know the path. You might expect 404, but when another route with the same prefix exists, Flask's routing can interpret it as "path matches but method doesn't" — hence 405 instead of 404.
The Fix
Added the corresponding endpoint near the existing simple-tasks routes in server.py:
@app.route('/api/simple-tasks/rename', methods=['POST'])
def simple_tasks_rename():
data = request.get_json()
project_id = data.get('project')
new_name = data.get('name')
if not project_id or not new_name:
return jsonify({'error': 'project and name required'}), 400
tasks_data = load_simple_tasks()
for proj in tasks_data.get('projects', []):
if proj['id'] == project_id:
proj['name'] = new_name
break
else:
return jsonify({'error': 'project not found'}), 404
save_simple_tasks(tasks_data)
return jsonify({'ok': True})
The Trap: Zombie Processes
After writing the fix and restarting Flask, the 405 persisted.
The culprit: the old Flask process was still holding the port. systemctl restart failed to properly kill the old process, and the new one couldn't start.
# Find and kill the culprit
fuser -k <PORT>/tcp
# Start fresh
systemctl --user start task-dashboard.service
Only then did the fix take effect.
Lesson: API Route Management in SPA + Custom Backend
When maintaining a 1000+ line SPA and a 2000+ line Flask backend solo (+ AI), forgetting to add the backend route when adding a frontend feature just happens.
Prevention
- Maintain an API route inventory. Keep an endpoint list in your README or project docs. Update it every time you add a route.
-
Grep your frontend fetch calls. Periodically run
grep -r "fetch\|axios\|/api/" index.htmland cross-reference against backend routes. -
Print routes on startup. Flask's
app.url_mapcan dump all routes to the startup log. -
Watch for zombie processes. When a fix doesn't take effect, check what's holding the port (
fuser/lsof -i).
# Print all routes on Flask startup
with app.test_request_context():
for rule in app.url_map.iter_rules():
print(f" {rule.methods} {rule.rule}")
Conclusion
405 Method Not Allowed means either "route doesn't exist" or "wrong method." When growing a custom API alongside an SPA, route mismatches between frontend and backend are inevitable. Maintain an API inventory and update both sides simultaneously.
And when your fix doesn't seem to take effect — check fuser first. Nine times out of ten, an old process is squatting on the port.
Top comments (0)