Roxabi Boilerplate
Guides

Troubleshooting

Common issues and solutions for Roxabi Boilerplate development

Common issues encountered during development and their solutions.

Database Connection Failures

Symptom: connection refused or ECONNREFUSED errors on port 5432 when starting the API or running migrations.

Cause: The PostgreSQL Docker container is not running, or is mapped to a different port than the app expects.

Fix: Start the Docker services and verify the container is healthy:

docker compose up -d
docker compose ps

Confirm the DATABASE_URL in your .env file matches the port and credentials defined in docker-compose.yml.

If you copied .env.example but changed nothing, verify the default credentials (roxabi:roxabi) match what docker-compose.yml defines. A common mistake is editing the password in one place but not the other:

# Verify by connecting manually
docker exec -it roxabi-postgres psql -U roxabi -d roxabi -c "SELECT 1"

Bun Version Mismatch

Symptom: error: package manager mismatch during install, or unexpected runtime behavior.

Cause: Your local Bun version does not match the packageManager field declared in the root package.json.

Fix: Upgrade Bun to the latest version, or install the exact version the project expects:

bun upgrade

If the project pins a specific version, check package.json for the packageManager field and install that version.

Port Already in Use

Symptom: EADDRINUSE error when starting the dev server or API.

Cause: Another process is already listening on port 3000 (web), 4000 (API), or 3001 (email preview).

Fix: Kill the process occupying the port, or start on a different port:

lsof -ti:3000 | xargs -r kill
lsof -ti:4000 | xargs -r kill
lsof -ti:3001 | xargs -r kill

Alternatively, set the PORT environment variable to use a different port.

Dependency Install Failures After Updates

Symptom: bun install fails with resolution errors, checksum mismatches, or bun.lock conflicts after pulling new changes or updating dependencies.

Cause: The local node_modules tree or bun.lock file is out of sync with the updated package.json files. This commonly happens after merging a branch that changed dependencies, or after a major Bun version upgrade that changes the lockfile format.

Fix:

Remove node_modules across the entire monorepo and reinstall from scratch:

# Remove all node_modules directories
rm -rf node_modules apps/*/node_modules packages/*/node_modules

# Regenerate the lockfile and install
bun install

If the lockfile itself is corrupted or has unresolvable conflicts:

rm bun.lock
bun install

Warning: Deleting bun.lock changes resolved dependency versions. Only do this if the lockfile has unresolvable merge conflicts. Run bun run typecheck && bun run test afterward to catch any version drift.

After reinstalling, verify everything builds:

bun run typecheck && bun run build

Authentication Not Working in Development

Symptom: Login succeeds (API returns 200) but the frontend still shows the user as unauthenticated. useSession() returns null. Requests to protected routes return 401 Unauthorized.

Cause: Better Auth uses cookie-based sessions. In development, the frontend (port 3000) and API (port 4000) run on different ports. The dev proxy configured in vite.config.ts at /api/** forwards requests to the API so that cookies stay on the same origin (localhost:3000). If the proxy is not active or the frontend client sends requests directly to localhost:4000, cookies are set on a different origin and the browser will not include them in subsequent requests.

Another common cause is a missing or default BETTER_AUTH_SECRET in .env. If the secret is not set, session tokens cannot be signed correctly.

Fix:

  1. Make sure bun dev is running for both the web and API apps (or use bun dev at the monorepo root, which starts both).

  2. Confirm the auth client in apps/web/src/lib/authClient.ts uses window.location.origin (not the API URL directly) as the baseURL. The default configuration does this correctly -- if you've modified it, revert to using window.location.origin.

If the API fails to start with a secret-related error, see BETTER_AUTH_SECRET Errors on Startup below.

  1. Check that the dev proxy is forwarding /api/** requests. Open DevTools Network tab, sign in, and confirm requests go to localhost:3000/api/auth/* (not localhost:4000).

For a full explanation of the cookie-based auth architecture, see the Authentication guide.

CORS Errors

Symptom: Browser console shows Access to fetch at 'http://localhost:4000/...' has been blocked by CORS policy or similar cross-origin errors.

Cause: The API's CORS_ORIGIN environment variable does not include the origin the browser is sending requests from. In development, CORS_ORIGIN defaults to http://localhost:3000. If you are accessing the frontend on a different host (e.g., 127.0.0.1:3000 or a custom domain), the origins will not match.

Another cause is making requests directly to the API (port 4000) from frontend code instead of going through the dev proxy. The proxy eliminates CORS entirely in development because both the page and the API appear to be on the same origin.

Fix:

  1. Ensure you access the frontend at http://localhost:3000 (not 127.0.0.1 or another hostname).

  2. Verify CORS_ORIGIN in .env matches the exact origin you use in the browser:

# .env
CORS_ORIGIN=http://localhost:3000

For multiple origins (e.g., staging and local), use a comma-separated list:

CORS_ORIGIN=http://localhost:3000,https://staging.example.com
  1. If you need to call the API directly (bypassing the proxy), ensure CORS_ORIGIN includes the origin your frontend is served from (e.g., http://localhost:3000). The value must match the browser's origin, not the API's address.

  2. In production, set CORS_ORIGIN to your exact frontend domain in the Vercel API project settings:

CORS_ORIGIN=https://app.yourdomain.com

In production, if CORS_ORIGIN contains only *, CORS will be disabled entirely (all cross-origin requests blocked). If * appears alongside valid origins, only the wildcard entry is removed. The API logs a warning in both cases.

BETTER_AUTH_SECRET Errors on Startup

Symptom: The API crashes on startup with an error about BETTER_AUTH_SECRET being invalid or set to a known default value.

Cause: In production (NODE_ENV=production), Better Auth validates that the secret is not a placeholder. The .env.example ships with BETTER_AUTH_SECRET=change-me-to-a-random-32-char-string, which is rejected in production mode.

Fix:

Generate a cryptographically random secret and set it in your .env:

# Generate a 32-character random secret
openssl rand -base64 32

Update your .env:

BETTER_AUTH_SECRET=<paste-your-generated-secret-here>

For Vercel deployments, set it in the API project's environment variables dashboard. A value of at least 32 characters is recommended.

For the full list of auth-related environment variables, see the Authentication guide.

Worktree Database Not Found

Symptom: After creating a git worktree, the API fails to start with a database error like database "roxabi_<number>" does not exist or migrations fail.

Cause: Each worktree is intended to use its own isolated branch database (roxabi_<issue_number>). The db:branch:create script creates this database, runs migrations, seeds it, and updates the worktree's .env with the correct DATABASE_URL. If you skipped this step, the worktree's .env still points to the default roxabi database (or worse, no database at all).

Fix:

Important: Run this from inside your worktree directory (e.g., ../roxabi-42/), not from the main repository checkout. Running from the wrong directory will update the wrong .env file.

cd apps/api
bun run db:branch:create --force <issue_number>

This will:

  • Create the roxabi_<issue_number> database in the Docker container
  • Run all migrations
  • Seed the database with dev data (dev@roxabi.local / password123)
  • Update your .env DATABASE_URL to point to the new database

If you already started working and need to check which branch databases exist:

cd apps/api
bun run db:branch:list

To clean up a branch database you no longer need:

cd apps/api
bun run db:branch:drop

For more on branch databases, see Configuration -- Branch Databases.

After Pulling Admin Panel Changes (PR #279)

If you had an existing Docker Postgres setup before this PR, the roxabi_app database user was not created automatically (Docker init scripts only run on first boot). Run:

bun run db:setup-app-user

This creates the roxabi_app user with RLS-enforced permissions. Without it, tenant-scoped queries will fail with "permission denied to set role app_user".

Alternative: delete your Docker volume and recreate: bun run db:down && docker volume rm roxabi_boilerplate_postgres_data && bun run db:up

Pre-commit Hook Failures

Symptom: Commit is rejected by Lefthook with Biome formatting errors or commitlint violations.

Cause: Staged files have formatting issues, or the commit message does not follow the Conventional Commits format.

Fix: For formatting issues, run Biome auto-fix across the project:

bunx biome check --write .

For commit message rejections, use the Conventional Commits format: type(scope): description (e.g., feat(web): add login page). See the Contributing guide for the full list of types.

TypeScript Build Errors After Dependency Updates

Symptom: Type errors appear after running bun install or updating packages, even though the code has not changed.

Cause: Stale .tsbuildinfo incremental compilation files or cached type definitions from previous dependency versions.

Fix: Clear the build cache and re-run the type checker:

# Remove stale incremental compilation files
find . -name '*.tsbuildinfo' -not -path '*/node_modules/*' -delete

bun run clean:cache && bun run typecheck

Turbo Cache Staleness

Symptom: Build succeeds but your changes do not appear in the output, or Turbo reports "cache hit" for code you just modified.

Cause: Turbo's content hash does not capture all inputs (e.g., environment variables or files outside the declared inputs).

Fix: Clear the Turbo cache and rebuild:

bun run clean:cache

Or remove the cache directory manually:

rm -rf .turbo

Then run your build command again.

We use cookies to improve your experience. You can accept all, reject all, or customize your preferences.