Cracking the “Cannot Resolve Provider” Crash on an Ubuntu VPS: My 48‑Hour Battle With Mismatched TypeORM Migrations 🌪️
Imagine launching a brand‑new Node.js service on a fresh Ubuntu VPS, only to watch it explode with the dreaded “Cannot resolve provider” error. My heart raced, the clock ticked, and the whole deployment pipeline threatened to stall forever. If you’ve ever stared at a red‑screen crash and felt the panic set in, keep reading. I’m about to spill the exact steps I took to tame that beast, save hours of debugging, and get my TypeORM migrations back on track.
Why This Matters
In the world of SaaS, every minute of downtime translates directly into lost revenue and eroded trust. A mismatched migration not only blocks new features but can also corrupt production data if you force a save. Understanding the root cause of the “Cannot resolve provider” crash means you can:
- Deploy updates without fear of breaking the database.
- Automate migrations safely in CI/CD pipelines.
- Turn a scary error into a repeatable, documented process.
Step‑by‑Step Tutorial: Taming the Crash
-
Re‑create the environment locally
Before you chase ghosts on the VPS, spin up a Docker container that mirrors the production stack (Node 18, Ubuntu 22.04, PostgreSQL 14). This isolates the problem and gives you fast feedback.
docker run -d \\ --name pg-test \\ -e POSTGRES_USER=dev \\ -e POSTGRES_PASSWORD=devpass \\ -e POSTGRES_DB=appdb \\ -p 5432:5432 \\ postgres:14-alpineThen connect your NestJS app to this container using the same
.envvalues you use on the VPS. -
Inspect the TypeORM config
Open
ormconfig.ts(ordatasource.tsif you’re on TypeORM 0.3+). The key culprit is usually a missingmigrationsRunflag or an outdatedentityPrefix.export const AppDataSource = new DataSource({ type: 'postgres', host: process.env.DB_HOST, port: +process.env.DB_PORT, username: process.env.DB_USER, password: process.env.DB_PASS, database: process.env.DB_NAME, entities: [__dirname + '/../**/*.entity{.ts,.js}'], migrations: [__dirname + '/../migrations/*{.ts,.js}'], // 👇 this flag forces TypeORM to run pending migrations at startup migrationsRun: true, });Tip: If you’re usingdotenv, load the file before importing the datasource. -
Identify the mismatched migration
Run the CLI with verbose output:
npm run typeorm migration:run -- -vThe console will show the exact SQL that failed. In my case, a migration tried to
ALTER TABLE users ADD COLUMN role varcharwhile theuserstable already contained arolecolumn from a previous, manually‑applied script. -
Fix the migration file
Open the offending file (
1649456789012-AddRoleToUser.ts) and make the changes idempotent:await queryRunner.query(` DO $$ BEGIN IF NOT EXISTS ( SELECT 1 FROM information_schema.columns WHERE table_name='users' AND column_name='role' ) THEN ALTER TABLE "users" ADD "role" varchar; END IF; END$$; `);Warning: Never edit a migration that’s already been executed in production unless you’re 100% sure you can roll back safely. -
Re‑run migrations on the VPS
SSH into the server, pull the latest code, and clear the TypeORM cache:
ssh root@your‑vps.ip cd /var/www/my‑app git pull origin main npm ci npm run build # Ensure the .env is correct npm run typeorm migration:run -- -vIf everything goes smoothly, you’ll see “Executed 1 migrations successfully”. No more “Cannot resolve provider” errors.
Real‑World Use Case: Auto‑Scaling a SaaS Dashboard
I was building a multi‑tenant dashboard that needed to add a tenant_id column to dozens of tables overnight. The migration strategy had to be 100 % repeatable because each new VM spun up a fresh copy of the database schema via Docker‑Compose.
By applying the idempotent pattern above, the same migration ran cleanly on brand‑new containers, on the production VPS, and even on the staging environment. The result? Zero manual DB fixes during the launch window, saving the team over 12 hours of grunt work.
Results / Outcome
- Crash eliminated after 48 hours of frantic debugging.
- Deployment time slashed from 30 min to under 5 min per release.
- Database integrity verified with a simple
npm test:e2esuite. - Team confidence restored – we now push migrations straight from CI.
Bonus Tips for Future‑Proofing Your TypeORM Migrations
- Version your migrations with timestamps. It prevents race conditions when multiple devs generate files simultaneously.
- Run migrations in a transaction. Set
transaction: 'all'in the migration options to roll back automatically on failure. - Add a health‑check endpoint. Return
SELECT 1from the DB; if it fails, auto‑restart the container. - Log every migration run. Store logs in
/var/log/app/migrations.logand ship them to a centralized log service. - Never commit compiled .js migration files. Keep only the source .ts; CI will compile them on the fly.
Monetization (Optional)
If you’re building a consultancy around DevOps automation, this exact troubleshooting workflow can be packaged as a “Rapid Migration Rescue” service. Charge a flat fee of $299 per incident or a monthly retainer for proactive monitoring. Add a short checkout button to your site and watch the leads roll in.
No comments:
Post a Comment