Skip to content

Troubleshooting

rocambille edited this page Jul 27, 2026 · 6 revisions

Summary: This page lists the most common mistakes encountered when working with StartER, with their symptoms and solutions.

What you'll learn:

  • Diagnose the most common StartER errors
  • Fix CSRF, routing, and schema mismatch issues
  • Identify where to look when something goes wrong

Route not found (404 on a new endpoint)

Symptom: you created a new module with make:clone, but requests to your new endpoint return 404.

Cause: the routes file was not registered in src/express/routes.ts (backend) or src/react/routes.tsx (frontend).

Solution:

// src/express/routes.ts
import postRoutes from "./modules/post/postRoutes";

router.use(postRoutes);

// src/react/routes.tsx
import { postRoutes } from "./components/post";
// ... add postRoutes to the children array

Important

make:clone creates the files but does not register them automatically. You must add the import yourself.

401 Unauthorized on POST / PUT / DELETE requests

Symptom: your GET requests work, but any mutation (POST, PUT, PATCH, DELETE) returns 401.

Cause: the CSRF token is missing. StartER uses a Client-Side Double-Submit pattern: every mutation request must include both a cookie and a matching header.

Solution for the browser: this is handled automatically by the useMutate() hook in src/react/helpers/mutate.ts. If you're making requests manually (e.g., with fetch), use the useMutate hook instead.

Solution for Postman / Insomnia:

  1. Add a header: x-csrf-token: test-token
  2. Add a cookie: __Host-x-csrf-token=test-token

The values must match. Their content doesn't matter for testing.

req.item is undefined (param converter not registered)

Symptom: your action crashes with Cannot read properties of undefined when accessing req.item (or req.post, etc.).

Cause: the param converter is not registered in the routes file.

Solution: make sure your routes file calls router.param():

// src/express/modules/post/postRoutes.ts
import postParamConverter from "./postParamConverter";

router.param("postId", postParamConverter.convert);

Without this line, Express doesn't know how to convert the :postId URL parameter into a loaded entity.

Schema mismatch after adding a column

Symptom: after adding a column to schema.sql, your API returns data without the new field, or TypeScript shows type errors.

Cause: you updated schema.sql but forgot one or more of these steps:

  1. Run npm run database:reset to recreate the database
  2. Update the type in src/types/index.d.ts
  3. Update the Zod schema in the repository
  4. Update the SQL queries in the repository (SELECT, INSERT, UPDATE)

Solution: follow the full checklist (see First exercises, Exercise 4). After modifying the type in index.d.ts, let TypeScript guide you: the compiler will flag every file that needs updating.

Tests fail after modifying a resource

Symptom: npm run test fails after adding or modifying a field on a resource.

Cause: the test fixtures and contracts don't know about the new field.

Solution: update both:

  1. tests/fixtures/items.ts : add the new field to each fixture object
  2. tests/contracts/items.ts : add the new field to the body of each mutation request (add, edit)

See First exercises, Exercise 5 for a step-by-step walkthrough.

npm run database:reset doesn't seem to work

Symptom: your schema changes don't take effect after running database:reset.

Possible causes:

  1. Syntax error in SQL: check your schema.sql for typos. SQLite will silently stop at the first error.
  2. Server still running: some operating systems lock the database file. Stop the dev server, run database:reset, then restart.
  3. Wrong database path: ensure you're running the command from the project root.

JWT / Authentication errors in development

Symptom: after restarting the server, you get 401 on previously authenticated requests.

Cause: the APP_SECRET was regenerated (or not set).

Solution: set a persistent APP_SECRET in your .env file:

APP_SECRET=your-development-secret-here

This ensures JWTs signed before a restart remain valid. Restart the server for the change to take effect.

SMTP_URL error on startup in production

Symptom: the server refuses to start and logs an error about SMTP_URL.

Cause: in production (NODE_ENV=production), StartER requires SMTP_URL to be defined. This is a safety check to ensure your application can actually send emails to users.

Solution: set SMTP_URL in your production environment:

SMTP_URL=smtp://user:password@smtp.example.com:587

In development, if SMTP_URL is not set, the magic link is printed to the console instead.

ReferenceError: window is not defined (or document / localStorage)

Symptom: the server crashes on initial request with ReferenceError: window is not defined during SSR.

Cause: accessing browser-only globals at the component top-level or outside useEffect.

Solution: wrap browser-only logic in useEffect (which runs exclusively on the browser) or guard with a type check:

// Good: runs only on client browser
useEffect(() => {
  const theme = localStorage.getItem("theme");
}, []);

// Alternative guard:
if (typeof window !== "undefined") {
  // Client-only execution
}

React Hydration Mismatch (Text content does not match server-rendered HTML)

Symptom: browser console warning stating server-rendered HTML does not match client DOM.

Cause: rendering dynamic values (e.g. new Date().toLocaleTimeString() or Math.random()) that produce different output on Node server vs client browser.

Solution: use stable initial props or format dates using StartER's datetime.ts helper with VITE_TIMEZONE.

SSR Network Fetch Errors (Absolute URL required)

Symptom: server-side loader fails with TypeError: Only absolute URLs are supported.

Cause: making raw fetch("/api/items") calls during server rendering without forwarding headers or base URL context.

Solution: use StartER's built-in getOrFetch(url) helper or forward request headers in loaders as shown in src/react/routes.tsx.

Best practices

  • Read the error message first: StartER's error responses include the HTTP status code and a descriptive message. Start there before searching the code.
  • Check the terminal: the dev server logs all errors with stack traces. The browser console only shows the HTTP status.
  • Use TypeScript as your checklist: after modifying a shared type, fix every TypeScript error before running the app. They are your TODO list.

See also

Clone this wiki locally