From a865da99a8086adb7551c70ac154f26dcd84745c Mon Sep 17 00:00:00 2001 From: Wuesteon Date: Thu, 4 Dec 2025 19:09:38 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=9D=20docs:=20add=20NestJS=20dependenc?= =?UTF-8?q?y=20injection=20troubleshooting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document the type-only import issue that causes "Nest can't resolve dependencies" errors. This was the root cause of the AiService injection failure that took significant debugging to identify. Key learnings: - Type-only imports are erased at compile time - NestJS needs actual class imports for DI - Docker cache can mask source code changes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- TROUBLESHOOTING.md | 136 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) diff --git a/TROUBLESHOOTING.md b/TROUBLESHOOTING.md index ed013834d..159369e2b 100644 --- a/TROUBLESHOOTING.md +++ b/TROUBLESHOOTING.md @@ -7,6 +7,7 @@ Common issues and solutions for the manacore-monorepo. - [Recursive Turbo Calls](#recursive-turbo-calls) - [Build Issues](#build-issues) - [Linting Issues](#linting-issues) +- [NestJS Dependency Injection](#nestjs-dependency-injection) --- @@ -269,6 +270,141 @@ done --- +## NestJS Dependency Injection + +### Problem: "Nest can't resolve dependencies" Error + +**Symptoms:** + +- NestJS fails to start with error: `Nest can't resolve dependencies of the XService (?)` +- Error mentions "argument Function at index [0] is available" +- The module imports look correct but service still won't inject + +**Root Cause:** + +Using **type-only imports** (`import { type X }`) for classes that need to be injected. TypeScript erases type-only imports at compile time, so the actual class is not available at runtime for dependency injection. + +### ❌ WRONG - Type-Only Import + +```typescript +// services/mana-core-auth/src/ai/ai.service.ts - DON'T DO THIS! +import { Injectable } from '@nestjs/common'; +import { type ConfigService } from '@nestjs/config'; // ❌ Type-only import + +@Injectable() +export class AiService { + constructor(private configService: ConfigService) { + // NestJS can't inject ConfigService because it was type-only imported! + } +} +``` + +**What happens:** + +1. TypeScript compiles the code +2. The `type` keyword tells TypeScript to erase the import at compile time +3. The compiled JS has NO import for ConfigService +4. At runtime, NestJS can't find the ConfigService class to inject +5. Error: "Nest can't resolve dependencies of the AiService (?)" + +### ✅ CORRECT - Regular Import + +```typescript +// services/mana-core-auth/src/ai/ai.service.ts - CORRECT +import { Injectable } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; // ✅ Regular import + +@Injectable() +export class AiService { + constructor(private configService: ConfigService) { + // ConfigService is properly imported and can be injected + } +} +``` + +### The Rule + +> **For NestJS dependency injection, NEVER use type-only imports (`import { type X }`) for classes you need to inject.** + +- ✅ `import { ConfigService }` - Regular import (works) +- ❌ `import { type ConfigService }` - Type-only import (breaks DI) +- ✅ `import type { MyInterface }` - Type-only for interfaces (fine, not injected) +- ✅ `import { type MyType, MyClass }` - Mixed (MyType erased, MyClass available) + +### How to Fix + +1. Find the service with the DI error +2. Check all imports for classes used in the constructor +3. Remove the `type` keyword from class imports: + +```diff + import { Injectable } from '@nestjs/common'; +- import { type ConfigService } from '@nestjs/config'; ++ import { ConfigService } from '@nestjs/config'; + + @Injectable() + export class AiService { + constructor(private configService: ConfigService) {} + } +``` + +4. Rebuild and test: + +```bash +pnpm --filter mana-core-auth build +pnpm --filter mana-core-auth start:dev +``` + +### Debugging + +If you're still getting DI errors after removing type-only imports: + +1. **Check the module imports the provider's dependencies:** + +```typescript +@Module({ + imports: [ConfigModule], // ← ConfigService needs ConfigModule + providers: [AiService], + exports: [AiService], +}) +export class AiModule {} +``` + +2. **Verify the compiled JavaScript:** + +```bash +# Build the service +pnpm --filter mana-core-auth build + +# Check the compiled output +cat services/mana-core-auth/dist/ai/ai.service.js | grep "require" + +# Should see: +# const config_1 = require("@nestjs/config"); ✅ Good +# NOT: +# const config_1 = undefined; ❌ Bad (type-only import) +``` + +3. **Check Docker builds:** + +If the error only happens in Docker but not locally: + +```bash +# Build Docker image without cache +docker build --no-cache -f services/mana-core-auth/Dockerfile -t test . + +# Check the compiled code in the image +docker run --rm --entrypoint cat test /app/dist/ai/ai.service.js +``` + +### Related Issues + +- [Commit d69cc607](https://github.com/Memo-2023/manacore-monorepo/commit/d69cc607) - Fixed type-only ConfigService import in AiService +- TypeScript `import type` vs `import { type }` - both erase at compile time +- Docker layer caching can hide fixes if source wasn't properly copied + +--- + ## References - [CLAUDE.md - Turborepo Configuration](./CLAUDE.md#turborepo-configuration)