📄 SKILL.md

← Vault

name: tanstack-start-vps-startup-script

description: Fix "Cannot read properties of undefined (reading 'fetch')" when deploying TanStack Start to VPS — server.fetch vs server.default.fetch gotcha

triggers:

- tanstack start server not starting

- Cannot read properties of undefined reading fetch

- tanstack start EADDRINUSE 3010


TanStack Start VPS Startup Script

The Gotcha

When you import the TanStack Start server build:

`js

import server from './dist/server/server.js'

`

You get:

The fetch handler is directly on the imported module as server.fetch, NOT under .default.

Working start-server.mjs

`js

import { createServer } from 'node:http';

import server from './dist/server/server.js';

const PORT = parseInt(process.env.PORT || '3010', 10);

const HOST = process.env.HOST || '0.0.0.0';

const httpServer = createServer(async (req, res) => {

try {

const baseUrl = http://${req.headers.host || ${HOST}:${PORT}};

const url = new URL(req.url, baseUrl);

// GET/HEAD cannot have body — must be null

const bodyAllowed = req.method !== 'GET' && req.method !== 'HEAD';

let body = null;

if (bodyAllowed) {

body = await new Promise((resolve, reject) => {

const chunks = [];

req.on('data', chunk => chunks.push(chunk));

req.on('end', () => resolve(Buffer.concat(chunks)));

req.on('error', reject);

});

}

const webReq = new Request(url, {

method: req.method,

headers: req.headers,

body,

duplex: 'half',

});

// Use server.fetch directly — NOT server.default.fetch

const webRes = await server.fetch(webReq);

const status = webRes.status;

const responseHeaders = Object.fromEntries(webRes.headers.entries());

res.writeHead(status, responseHeaders);

if (webRes.body) {

for await (const chunk of webRes.body) {

res.write(chunk);

}

}

res.end();

} catch (err) {

console.error('Request error:', err.message);

res.writeHead(500, { 'Content-Type': 'text/plain' });

res.end('Internal Server Error');

}

});

httpServer.listen(PORT, HOST, () => {

console.log(Server running on ${HOST}:${PORT});

});

process.on('SIGTERM', () => httpServer.close(() => process.exit(0)));

`

Common error patterns

ErrorCause
--------------
Cannot read properties of undefined (reading 'fetch')Used server.default.fetch instead of server.fetch
Request with GET/HEAD method cannot have bodyPassed req (stream) as body for GET requests — must be null
EADDRINUSE 0.0.0.0:3010 after killing old processOld node process respawned (systemd/docker), use fuser -k 3010/tcp or find and kill parent

Port conflicts

Before starting, always kill existing processes:

`bash

fuser -k 3010/tcp 2>/dev/null; sleep 1

`

Verify method

Test with direct curl before Nginx proxy:

`bash

curl -s http://127.0.0.1:3010/ -I | head -5

Should show HTTP/1.1 200 OK (or redirect)

`

Build first if routes changed

If you add new API routes, rebuild first:

`bash

cd /path/to/app && nvm use 20 && npm run build

`

Then restart the server.