{"record":{"id":"6ff41f25ccb5b8fc","repo":"paperclipai/paperclip","slug":"upgrade-required","errorCode":null,"errorMessage":"Upgrade Required","messagePattern":"Upgrade Required","errorType":"http","errorClass":null,"httpStatus":426,"severity":"info","filePath":"server/src/app.ts","lineNumber":1013,"sourceCode":"          return;\n        }\n        res\n          .status(200)\n          .set(\"Content-Type\", \"text/html\")\n          .set(\"Cache-Control\", \"no-cache\")\n          .end(readBrandedStaticIndexHtml(uiDist));\n      });\n    } else {\n      console.warn(\"[paperclip] UI dist not found; running in API-only mode\");\n    }\n    if (process.env.PAPERCLIP_MANAGED_RUNTIME_EXPOSURE === \"tailscale_https\") {\n      // The managed-runtime supervisor waits for the app port AND its derived\n      // Vite HMR companion port to bind before publishing the service. Static\n      // mode has no Vite, so bind the same placeholder listener dev mode uses\n      // or the supervisor kills a healthy server at the readiness deadline\n      // (PAP-18043).\n      const hmrServer = createHttpServer((_req, res) => {\n        res.writeHead(426, { \"Content-Type\": \"text/plain\" });\n        res.end(\"Upgrade Required\");\n      });\n      await listenViteHmrServer(\n        hmrServer,\n        resolveViteHmrPort(opts.serverPort),\n        opts.bindHost,\n      );\n      viteHmrServer = hmrServer;\n    }\n  }\n\n  if (opts.uiMode === \"vite-dev\") {\n    const uiRoot = path.resolve(__dirname, \"../../ui\");\n    const publicUiRoot = path.resolve(uiRoot, \"public\");\n    const hmrPort = resolveViteHmrPort(opts.serverPort);\n    const hmrHost = resolveViteHmrHost(opts.bindHost);\n    const hmrProtocol = resolveViteHmrProtocol(\n      process.env.PAPERCLIP_VITE_HMR_PROTOCOL,","sourceCodeStart":995,"sourceCodeEnd":1031,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/server/src/app.ts#L995-L1031","documentation":"In static (non-dev) mode the server still must bind a placeholder listener on the derived Vite HMR port so the managed-runtime supervisor's readiness check (which waits for both ports) does not kill a healthy server (PAP-18043). That placeholder handler responds 426 Upgrade Required to any request because there is no Vite/HMR to serve in static mode.","triggerScenarios":"Hitting the derived HMR port (resolved from the main server port) while the server runs in static mode; a health/probe or browser tab pointed at the HMR port instead of the app port.","commonSituations":"Configuring a proxy or load balancer to the HMR companion port; opening the wrong port in a browser during local static-mode runs; monitoring checks scanning all listening ports.","solutions":["Send requests to the main server port, not the derived Vite HMR port","Update any proxy/monitor to target the application port; treat the HMR port as internal/supervisor-only","If you need HMR, run in dev mode where a real Vite server binds that port"],"exampleFix":"// before\ncurl http://localhost:3101/  # derived HMR port in static mode -> 426\n// after\ncurl http://localhost:3100/  # main app port","handlingStrategy":"type-guard","validationCode":"const isMainAppPort = (port: number, serverPort: number) => port === serverPort;\nif (!isMainAppPort(targetPort, configuredServerPort)) console.warn(\"target is the placeholder HMR port; expect 426 in static mode\");","typeGuard":"const isUpgradeRequired = (res: Response) => res.status === 426;","tryCatchPattern":"const res = await fetch(hmrUrl); if (res.status === 426) { /* wrong port in static mode: use the main server port */ }","preventionTips":["Point clients, proxies, and monitors at the main server port, never the derived HMR port","Treat the derived Vite HMR port as supervisor-internal in static mode","Document the port derivation (serverPort -> hmrPort) so operators avoid probing it","Run dev mode if you need a live Vite/HMR endpoint on that port"],"tags":["http","dev-server","readiness"],"backgroundTag":"unexpected-http-status","analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}