windmill-labs/windmill · warning

not found

Error message

not found

What it means

multiplayer/server.mjs's HTTP handler only answers known routes (like the /health-style endpoint that returns { status: 'ok', service: 'multiplayer' }); anything else falls into the else branch which writes 404 and ends with the body 'not found'. It is the server's catch-all for unrecognized HTTP paths.

Source

Thrown at multiplayer/server.mjs:272

// --- HTTP + WebSocket server ---

const server = http.createServer((req, res) => {
  // Strip /ws_mp/ prefix if present (when accessed without reverse proxy path stripping)
  if (req.url?.startsWith('/ws_mp/')) {
    req.url = req.url.slice('/ws_mp'.length)
  } else if (req.url === '/ws_mp') {
    req.url = '/'
  }
  console.log(`[${new Date().toISOString()}] HTTP ${req.method} ${req.url} from=${req.socket.remoteAddress}`)
  if (req.url === '/' || req.url === '/health') {
    res.writeHead(200, {
      'Content-Type': 'application/json',
      'Access-Control-Allow-Origin': '*'
    })
    res.end(JSON.stringify({ status: 'ok', service: 'multiplayer' }))
  } else {
    res.writeHead(404)
    res.end('not found')
  }
})

const wss = new WebSocketServer({ server })

wss.on('connection', async (ws, req) => {
  let docName = req.url?.slice(1).split('?')[0] || 'unknown'

  // Strip ws_mp/ prefix if present (when accessed without reverse proxy path stripping)
  if (docName.startsWith('ws_mp/')) {
    docName = docName.slice('ws_mp/'.length)
  }

  const clientIp = req.socket.remoteAddress

  // Handle ping test — respond and close immediately
  if (docName === '__ping__') {

View on GitHub (pinned to e474e8803c)

Solutions

  1. Check the requested path against the routes handled in multiplayer/server.mjs and correct the URL
  2. If a health check, point it at the implemented status route that returns { status: 'ok', service: 'multiplayer' }
  3. If a new route is needed, add it to the HTTP handler's if/else chain before the 404 fallback
  4. Verify the request targets the multiplayer HTTP port, not the WebSocket-only path

Example fix

// before
fetch('http://host:port/healthz')   // 404 'not found'
// after
fetch('http://host:port/health')    // 200 { status: 'ok', service: 'multiplayer' }
Defensive patterns

Strategy: validation

Validate before calling

// verify the route exists before calling
const KNOWN_ROUTES = ['/health'];
if (!KNOWN_ROUTES.includes(pathname)) throw new Error(`unknown multiplayer route: ${pathname}`);

Try / catch

const res = await fetch(url);
if (res.status === 404) {
  const body = await res.text(); // 'not found'
  throw new Error(`multiplayer server has no route for ${url.pathname}: ${body}`);
}

Prevention

When it happens

Trigger: An HTTP request hits the multiplayer server on a path that does not match any handled route — typo'd URL, wrong base path, request sent to the HTTP port instead of the WebSocket endpoint, or a health-check configured against a nonexistent path.

Common situations: Monitoring/probe pointed at the wrong path; client configured with an outdated route; someone curl-ing the health endpoint with a trailing typo (e.g. /heath); gateway forwarding paths the server does not implement.

Related errors


AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03). Data as JSON: /api/errors/fe43785248478502. Report an issue: GitHub.