DEV Community

Daniel Ioni
Daniel Ioni

Posted on

From `MODULE_NOT_FOUND` to a Verified AI Token Balance: Debugging MyZubster

From MODULE_NOT_FOUND to a Verified AI Token Balance: Debugging MyZubster

A small backend deployment issue turned into a useful debugging session.

While working on MyZubster, my Node.js/Express backend, the application initially failed to load because several route modules referenced by server.js did not exist at the expected paths.

The first error

The first failure was:

Error: Cannot find module './src/routes/geocodeRoutes'
Enter fullscreen mode Exit fullscreen mode

The server contained:

const geocodeRoutes = require('./src/routes/geocodeRoutes');
app.use('/api/geocode', geocodeRoutes);
Enter fullscreen mode Exit fullscreen mode

But the actual route file available in the project was:

src/routes/mapRoutes.js
Enter fullscreen mode Exit fullscreen mode

The route itself was valid and exported an Express router:

const express = require('express');
const router = express.Router();

router.get('/', (req, res) => {
  res.json({ message: 'Map routes - placeholder' });
});

module.exports = router;
Enter fullscreen mode Exit fullscreen mode

So the first fix was simply aligning the import with the actual file:

const geocodeRoutes = require('./src/routes/mapRoutes');
Enter fullscreen mode Exit fullscreen mode

The next missing module

After fixing that, Node.js exposed another missing dependency:

Error: Cannot find module './src/routes/healthRoutes'
Enter fullscreen mode Exit fullscreen mode

There was no healthRoutes.js in src/routes.

However, the project already had the health/status endpoints in:

src/api/routes.js
Enter fullscreen mode Exit fullscreen mode

That file contained endpoints such as:

router.get('/health', (req, res) => {
  res.json({
    status: 'ok',
    timestamp: new Date().toISOString(),
    uptime: process.uptime()
  });
});
Enter fullscreen mode Exit fullscreen mode

Instead of creating a duplicate route file, I reused the existing API router:

const healthRoutes = require('./src/api/routes');
Enter fullscreen mode Exit fullscreen mode

and mounted it with:

app.use('/', healthRoutes);
Enter fullscreen mode Exit fullscreen mode

This made the server load successfully:

SERVER LOAD OK
✅ Connected to MongoDB
Enter fullscreen mode Exit fullscreen mode

Verifying the AI forwarding API

The next issue was that the AI balance endpoint initially returned:

{
  "success": true,
  "userId": "DanielIoni-creator",
  "model": "deepseek-chat",
  "totalRemaining": 0,
  "contracts": []
}
Enter fullscreen mode Exit fullscreen mode

That suggested the route was working, but the database query wasn't finding the expected contract.

The controller uses:

const contracts = await AIContract.find({
  userId,
  model,
  status: 'active',
  expiresAt: { $gte: new Date() }
});
Enter fullscreen mode Exit fullscreen mode

The AIContract model stores:

userId: String
model: String
tokens: Number
consumedTokens: Number
status: String
expiresAt: Date
Enter fullscreen mode Exit fullscreen mode

So the next step was to inspect the actual MongoDB data rather than changing the controller blindly.

Finding the real database configuration

The application was using:

mongoose.connect(
  process.env.MONGO_URI || 'mongodb://localhost:27017/myzubster'
);
Enter fullscreen mode Exit fullscreen mode

But .env contained:

MONGODB_URI=...
Enter fullscreen mode Exit fullscreen mode

rather than MONGO_URI.

That explained why standalone diagnostic scripts using:

process.env.MONGO_URI
Enter fullscreen mode Exit fullscreen mode

received:

undefined
Enter fullscreen mode Exit fullscreen mode

The important lesson here was to distinguish between:

  • the variable name used by the application;
  • the variable name actually present in .env;
  • and the environment inherited by PM2.

After aligning the environment configuration, the database could be queried correctly.

The contract was there

The MongoDB inspection showed exactly one AI contract:

userId:          DanielIoni-creator
model:           deepseek-chat
tokens:          1,000,000
consumedTokens:  12,000
remaining:      988,000
status:           active
expiresAt:        2026-11-29T23:00:00.000Z
Enter fullscreen mode Exit fullscreen mode

This was the key verification point.

The data wasn't missing. The API route and controller logic were also correct. The problem was the environment/configuration used during the diagnostic process.

Final production verification

After restarting the PM2 process:

pm2 flush myzubster
pm2 restart myzubster --update-env
Enter fullscreen mode Exit fullscreen mode

the application remained online:

status: online
script path: /root/myzubster/server.js
Enter fullscreen mode Exit fullscreen mode

The health endpoint returned successfully:

{
  "status": "ok",
  "timestamp": "2026-08-16T06:33:25.195Z",
  "uptime": 18.952552298
}
Enter fullscreen mode Exit fullscreen mode

And the AI balance endpoint finally returned:

{
  "success": true,
  "userId": "DanielIoni-creator",
  "model": "deepseek-chat",
  "totalRemaining": 988000,
  "contracts": [
    {
      "id": "6a7fe1a8eba8e2f854ea2eb3",
      "remaining": 988000,
      "expiresAt": "2026-11-29T23:00:00.000Z"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

What this debugging session reinforced

A few simple practices made the difference:

  1. Check the filesystem before creating new modules.
    A missing geocodeRoutes.js turned out to be an existing mapRoutes.js.

  2. Don't duplicate existing routes.
    The health endpoints already existed in src/api/routes.js.

  3. Separate application errors from diagnostic-script errors.
    A standalone script failing because MONGO_URI was undefined did not necessarily mean the running application had the same problem.

  4. Inspect the actual database state.
    Before changing business logic, verify whether the expected records exist.

  5. Test through the real HTTP endpoint.
    The final curl request was the most important verification because it tested the complete chain:

   HTTP → Express → route → controller → Mongoose → MongoDB → JSON response
Enter fullscreen mode Exit fullscreen mode

Final result

The MyZubster backend is now loading correctly under PM2, MongoDB is connected, the health endpoints respond successfully, and the AI forwarding balance endpoint correctly reports:

988,000 remaining tokens.

What initially looked like an application/database problem ultimately came down to a combination of route-path mismatches and environment-variable consistency.

For me, the biggest takeaway is simple: before rewriting logic, verify the filesystem, environment, database, and actual HTTP response one layer at a time.

Top comments (0)