When Your Frontend Hits an API That Doesn't Exist — Debugging 405 Method Not Allowed
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.
Symptoms
Inline-editing a project name 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.
- 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. 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:
@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 old Flask process was still holding the port. systemctl restart failed to properly kill it.
fuser -k <PORT>/tcp
systemctl --user start task-dashboard.service
Prevention
- Maintain an API route inventory in your README
- Grep frontend fetch calls periodically and cross-reference against backend routes
- Print routes on startup using Flask's
app.url_map - Watch for zombie processes — when a fix doesn't take effect, check the port with
fuser/lsof -i
Conclusion
405 means either route doesn't exist or wrong method. When growing a custom API alongside an SPA, route mismatches are inevitable. Maintain an API inventory and update both sides simultaneously. And when your fix doesn't take effect — check fuser first.