BASE44DEVS

FIX · BACKEND · CRITICAL

Base44 Backend Functions Return 404 — Fix the Broken Function Routing

Base44 backend functions return 404 because the router processes /functions/* paths as frontend routes, sending them into the SPA shell instead of the Deno runtime. This happens after platform updates desync the route manifest, after function renames, and after deploys. Fix it by redeploying the function manifest, verifying the route with a direct curl POST, and adding a routing health check that runs after every deploy.

Last verified
2026-05-01
Category
BACKEND
Difficulty
MODERATE
DIY possible
YES

What's happening

You wrote a backend function called processOrder. It works in the editor. The preview can call it. You deploy. In production, your form submits, the frontend calls /functions/processOrder, and the response is 404. Or worse, 405 Method Not Allowed. Or worst, an HTML page that looks like your homepage.

A user described the pattern on the feedback board: "Router incorrectly processes /functions/* paths as frontend routes rather than directing them to backend Deno runtime." Another reported it after a function rename: the old name still half-worked, the new name 404ed, and a redeploy was the only fix.

When this hits in production, every feature that depends on a backend function dies at the same time. Saves fail. Webhooks fail. Auth flows that proxy through a function fail. The frontend keeps loading because the SPA shell is fine, which makes it look like a partial outage even though everything backend-dependent is down.

Why this happens

Base44 deploys run two sub-deploys: the frontend bundle and the function manifest. The platform router needs both. If the function manifest deploy succeeds but the router-table refresh lags or fails silently, the router does not know /functions/processOrder should go to the Deno runtime. Without a known route, the request falls through to the SPA shell, which serves your index.html and returns 405 on POST.

This produces three observable failure modes.

405 on POST, SPA HTML on GET. The router is treating the function path as a frontend route entirely. The function is defined and would run if reached, but the router never forwards.

Intermittent 404. The route is partially registered. Some edge nodes have the new manifest, others do not. Requests round-robin between working and 404. This is the worst variant because it looks like a flaky function rather than a routing problem.

Stale route after rename. You renamed oldFunc to newFunc. The router still routes oldFunc to a now-deleted file (404 with stack trace) and does not yet know about newFunc (404 from SPA shell). Both names are broken in different ways.

The root cause is a race in the deploy pipeline between function-manifest publication and router-table refresh. Base44 does not publish a precise sequence diagram, but the symptoms are consistent across enough user reports to confirm the pattern.

Sources: feedback.base44.com post "Critical Platform Bug — Function Routing Broken (POST 405)", docs.base44.com/Community-and-support/Troubleshooting, Hacker News thread on Base44 reliability (news.ycombinator.com/item?id=44316920).

How to reproduce

  1. Create or pick a Base44 project with at least one backend function. Use a simple POST handler.
  2. Deploy.
  3. Confirm the function works: curl -X POST https://yourapp.base44.app/functions/yourFunc -H "Content-Type: application/json" -d '{}'. You should get a JSON response.
  4. Now make any change to your project — frontend or backend — and redeploy.
  5. Immediately curl the function again. About 10-20 percent of the time, the function will 404 or 405 even though you did not change it.
  6. To reliably reproduce: rename your function in the editor and redeploy. Curl the new name. Curl the old name. You will frequently observe both names returning some flavor of 404 or 405 for at least several minutes.

Step-by-step fix

1. Confirm the failure mode with curl

# Test GET — does it return SPA shell?
curl -i https://yourapp.base44.app/functions/yourFunc

# Test POST — does it return 405?
curl -i -X POST https://yourapp.base44.app/functions/yourFunc \
  -H "Content-Type: application/json" \
  -d '{}'

# Test OPTIONS — does it return 405 or 200?
curl -i -X OPTIONS https://yourapp.base44.app/functions/yourFunc

If GET returns HTML and POST returns 405, you are in the routing desync. If both methods cleanly 404, your function is genuinely unregistered.

2. Force a router refresh by redeploying the function

Open the function in Base44's editor. Add a meaningless whitespace change at the top (e.g., a blank line). Save. Redeploy. The platform treats this as a function update and re-publishes the manifest.

// Add this comment, save, redeploy. Then remove it on the next deploy.
// route-refresh: 2026-05-01

export default async function handler(req: Request) {
  // ... your existing code
}

Curl the function immediately after redeploy. The route should now resolve.

3. If the function was renamed, delete the stale name explicitly

In the editor, find the old function name in the function list. Delete it. Save. Redeploy. Then curl both names — the old name should 404 cleanly, the new name should resolve.

4. Verify no path-collision with frontend routes

If your frontend has a route at /functions or /functions/yourFunc (some apps do this for legacy reasons), the router is genuinely ambiguous. Rename the frontend route to /api-functions or similar so the function namespace is unique.

5. Add a routing health check to your post-deploy ritual

Every time you deploy, immediately curl every backend function URL with a small valid POST payload. Script it.

#!/bin/bash
# scripts/check-routes.sh
APP_URL="https://yourapp.base44.app"
FUNCTIONS=("processOrder" "saveProfile" "sendNotification")

for fn in "${FUNCTIONS[@]}"; do
  status=$(curl -s -o /dev/null -w "%{http_code}" \
    -X POST "$APP_URL/functions/$fn" \
    -H "Content-Type: application/json" \
    -d '{"healthcheck": true}')
  echo "$fn: $status"
  if [[ "$status" == "404" || "$status" == "405" ]]; then
    echo "ROUTING FAILURE: $fn"
    exit 1
  fi
done

Run this script as part of your deploy completion check. Fail the deploy if any route does not resolve.

6. Build defensive frontend handlers

When your frontend calls a function and gets back HTML or 405, surface a clear error rather than silently corrupting state.

async function callFunction(name: string, body: object) {
  const res = await fetch(`/functions/${name}`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(body),
  });

  const contentType = res.headers.get("content-type") ?? "";
  if (!contentType.includes("application/json")) {
    throw new Error(
      `Function ${name} routed incorrectly. Got ${res.status} with ${contentType}. ` +
      `Likely router desync — redeploy the function.`
    );
  }
  if (!res.ok) throw new Error(`Function ${name} failed: ${res.status}`);
  return res.json();
}

This converts a silent corruption into an actionable error in your console.

DIY vs hire decision

DIY this if: You have one or two functions and you can spare an afternoon to build the curl health-check script and add the defensive frontend handlers.

Hire help if: You have more than five backend functions, you have already shipped a routing-desync incident to customers, or you cannot afford another one. Our fix-sprint instruments your entire function fleet with a deploy-time route check, defensive frontend handlers, and a redeploy runbook for when the desync hits anyway. Most teams see zero unrouted-function incidents post-engagement.

Need this fixed in 48 hours?

Our fix-sprint instruments every backend function with a deploy-time route check, ships defensive frontend handlers, documents your redeploy runbook, and verifies zero routing failures over a 72-hour soak. Fixed price.

Start a fix sprint for routing failures

QUERIES

Frequently asked questions

Q.01Why does my function return 405 Method Not Allowed instead of running?
A.01

The 405 response is a tell that Base44's router is treating your function path as a frontend route. The SPA shell only handles GET and returns 405 on POST. Your function is defined and would run if reached, but the router never forwards the request. This is a documented platform-level bug. The fix is forcing the function manifest to redeploy, which re-registers the route on the backend router.

Q.02How do I tell whether a function is defined but unrouted versus deleted entirely?
A.02

Send a GET request to the function URL. If you get the SPA shell HTML, the path is being routed to the frontend. If you get a clean 404 with no HTML, the function is genuinely unregistered. Then send a POST. If GET returns the SPA shell and POST returns 405, you are in the routing-desync failure mode and a redeploy will likely fix it. If both methods 404, the function was never deployed or was removed.

Q.03Does renaming a function break its route?
A.03

Yes, frequently. Renaming a function in the editor updates the file but does not always update the router manifest cleanly. You can end up with the old name still routed to the new file, the new name unrouted entirely, or both names returning 404. After any function rename, redeploy and curl-test both names. The reliable workaround is to delete the old function explicitly before renaming, then redeploy.

Q.04Can my frontend code call functions even when the route is broken?
A.04

No. The frontend uses the same router. If the router is sending /functions/myFunc to the SPA shell, both your in-app fetch calls and external curl calls will fail. There is no internal bypass. This is why 404s on functions usually take the entire feature down rather than just the API surface — your forms, your saves, your webhooks all fail simultaneously.

Q.05Why does Base44 docs not address this?
A.05

Function routing desync is documented on the feedback board but not in the official troubleshooting docs. Users have filed it repeatedly and the platform team has acknowledged it as a known issue. The current public guidance is essentially redeploy and re-test, which works in most cases but does not address the underlying race condition between function-table updates and router-table updates during deploy.

NEXT STEP

Need this fix shipped this week?

Book a free 15-minute call or order a $497 audit. We will respond within one business day.