Build Failures
Build Failures
Section titled “Build Failures”Observable Symptoms
Section titled “Observable Symptoms”- TypeScript compilation errors
- Docker build failures
- npm/pnpm install errors
- Missing module errors
- Import resolution failures
Quick Fix
Section titled “Quick Fix”# Clean and rebuildrm -rf dist/ node_modules/pnpm installpnpm run build
# Docker build with no cachedocker compose build --no-cache my-service
# Check build logspnpm run build 2>&1 | tee build.loggrep -i "error" build.logCommon Causes (Ordered by Frequency)
Section titled “Common Causes (Ordered by Frequency)”1. Missing .js Extension in Imports
Section titled “1. Missing .js Extension in Imports”Frequency: Very Common (40% of cases)
Symptoms:
- Build succeeds but runtime error: “Cannot find module”
- Error:
ERR_MODULE_NOT_FOUND - Imports work in development but fail in production
Diagnostic Steps:
# Find imports without .js extensiongrep -r "from ['\"]\..*[^\.js]['\"]" src/
# Should find lines like:# import { User } from './User'# import { config } from '../config'Examples:
// ❌ WRONG: Missing .js extensionimport { BusinessError } from '../errors';import { UserAggregate } from './domain/User';import { config } from '../config';
// ✓ CORRECT: Has .js extensionimport { BusinessError } from '../errors.js';import { UserAggregate } from './domain/User.js';import { config } from '../config.js';Why Required:
ES modules in Node.js require explicit file extensions. TypeScript doesn’t add them automatically.
Solution:
Add .js extension to all relative imports:
# Manual fix# Edit each file to add .js
# Or use find/replace in editor# Find: from ['"](\./[^'"]+)['"]# Replace: from '$1.js'Automated Fix:
# Use eslint rule to enforce{ "rules": { "import/extensions": ["error", "always", { "js": "always" }] }}Prevention:
- Configure editor to add .js automatically
- Use linter rule to catch missing extensions
- Review imports in code review
2. Platform Package Version Mismatch
Section titled “2. Platform Package Version Mismatch”Frequency: Very Common (30% of cases)
Symptoms:
- Type errors between platform packages
- “Types have separate declarations of a private property”
- Incompatible package versions
- Build succeeds but runtime errors
Diagnostic Steps:
# Check platform package versionsgrep "@banyanai/platform-" package.json | grep version
# Should all be same version# ❌ BAD:# "@banyanai/platform-core": "^1.0.115"# "@banyanai/platform-cqrs": "^1.0.110"
# ✓ GOOD:# "@banyanai/platform-core": "^1.0.116"# "@banyanai/platform-cqrs": "^1.0.116"Solution:
Update all platform packages to same version:
{ "dependencies": { "@banyanai/platform-base-service": "^1.0.116", "@banyanai/platform-core": "^1.0.116", "@banyanai/platform-cqrs": "^1.0.116", "@banyanai/platform-message-bus-client": "^1.0.116", "@banyanai/platform-event-sourcing": "^1.0.116", "@banyanai/platform-telemetry": "^1.0.116" }}Reinstall:
rm -rf node_modules/ pnpm-lock.yamlpnpm installpnpm run buildPrevention:
- Use exact versions in production:
"1.0.116"instead of"^1.0.116" - Update all packages together
- Use renovate/dependabot to keep versions in sync
3. Type-Only Import for Decorators
Section titled “3. Type-Only Import for Decorators”Frequency: Common (15% of cases)
Symptoms:
- Error: “Cannot use namespace as a value”
- Decorator metadata errors
- Build fails when using contract in decorator
Diagnostic Steps:
// Check imports for decoratorsgrep -A 5 "@CommandHandlerDecorator\|@QueryHandlerDecorator" src/
// Look for "import type" in those linesExamples:
// ❌ WRONG: Type-only importimport type { CreateUserCommand } from '../contracts/commands.js';
@CommandHandlerDecorator(CreateUserCommand) // ERROR: Cannot use type as valueexport class CreateUserHandler { }
// ✓ CORRECT: Value importimport { CreateUserCommand } from '../contracts/commands.js';
@CommandHandlerDecorator(CreateUserCommand) // OK: Has runtime valueexport class CreateUserHandler { }Solution:
Change type-only imports to value imports for decorators:
// For decorator arguments, use value importsimport { CreateUserCommand } from '../contracts/commands.js';
// Type-only imports OK for type annotationsimport type { CreateUserInput } from '../types.js';
@CommandHandlerDecorator(CreateUserCommand) // Needs valueexport class CreateUserHandler { async handle(input: CreateUserInput) { // Type annotation OK // ... }}Prevention:
- Never use
import typefor decorator arguments - Use linter rule to catch type-only imports of contract classes
- Document import requirements in team guidelines
4. Missing TypeScript Configuration
Section titled “4. Missing TypeScript Configuration”Frequency: Common (10% of cases)
Symptoms:
- Decorators not emitted
- Module resolution errors
- Import errors
- “Cannot find module” at runtime
Diagnostic Steps:
# Check tsconfig.json existscat tsconfig.json
# Verify key settingsjq '.compilerOptions | { experimentalDecorators, emitDecoratorMetadata, module, moduleResolution}' tsconfig.jsonRequired Settings:
{ "compilerOptions": { // REQUIRED for decorators "experimentalDecorators": true, "emitDecoratorMetadata": true,
// REQUIRED for ES modules "target": "ES2022", "module": "Node16", "moduleResolution": "Node16",
// Recommended "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "resolveJsonModule": true, "declaration": true, "outDir": "./dist", "rootDir": "./src" }, "include": ["src/**/*"], "exclude": ["node_modules", "dist", "**/*.test.ts"]}Solution:
Use provided tsconfig.json template or ensure all required options present:
# Copy from templatecp microservice-template/tsconfig.json .
# Or update existing configVerify Build Output:
# Build and check decorator metadatapnpm run buildcat dist/commands/CreateUserHandler.js | grep -A 5 "__decorate"
# Should see decorator metadataPrevention:
- Don’t modify critical compiler options
- Use provided tsconfig.json template
- Run type checking in CI/CD
5. Missing Dependencies
Section titled “5. Missing Dependencies”Frequency: Occasional (3% of cases)
Symptoms:
- “Cannot find module ‘@banyanai/platform-*’”
- npm/pnpm install failures
- Package not found errors
Diagnostic Steps:
# Check package.json dependenciescat package.json | jq '.dependencies'
# Try installingpnpm install
# Check for errorspnpm install 2>&1 | grep -i "error\|fail"Common Issues:
A. Missing Platform Package:
// package.json missing required dependency{ "dependencies": { "@banyanai/platform-core": "^1.0.116" // Missing: @banyanai/platform-cqrs }}B. Registry Authentication:
# Platform packages require authentication# Check .npmrccat .npmrc
# Should have:@banyanai:registry=https://npm.pkg.github.com//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}C. NODE_AUTH_TOKEN Not Set:
# Check tokenecho $NODE_AUTH_TOKEN
# If empty, set itexport NODE_AUTH_TOKEN=$(gh auth token)
# Or add to .envecho "NODE_AUTH_TOKEN=$(gh auth token)" >> .envSolution:
- Add missing dependencies to package.json
- Ensure .npmrc configured correctly
- Set NODE_AUTH_TOKEN environment variable
- Reinstall:
export NODE_AUTH_TOKEN=$(gh auth token)rm -rf node_modules/ pnpm-lock.yamlpnpm installPrevention:
- Document authentication requirements
- Use .npmrc template
- Check dependencies in package.json
6. Docker Build Cache Issues
Section titled “6. Docker Build Cache Issues”Frequency: Occasional (2% of cases)
Symptoms:
- Docker build uses outdated dependencies
- Changes not reflected in built image
- Stale node_modules in container
Diagnostic Steps:
# Check Docker build cachedocker image ls | grep my-service
# Check .dockerignorecat .dockerignore
# Should exclude:# node_modules# */node_modules# distSolution:
A. Build with No Cache:
docker compose build --no-cache my-serviceB. Update .dockerignore:
node_modules*/node_modulesdist*/dist.git.env.npmcoverage*.logC. Multi-Stage Build:
# DockerfileFROM node:20-alpine AS builder
WORKDIR /app
# Copy package filesCOPY package.json pnpm-lock.yaml ./
# Install dependenciesRUN npm install -g pnpmRUN pnpm install --frozen-lockfile
# Copy sourceCOPY . .
# BuildRUN pnpm run build
# Production stageFROM node:20-alpine
WORKDIR /app
# Copy package filesCOPY package.json pnpm-lock.yaml ./
# Install production dependencies onlyRUN npm install -g pnpmRUN pnpm install --frozen-lockfile --prod
# Copy built artifactsCOPY --from=builder /app/dist ./dist
CMD ["node", "dist/index.js"]Prevention:
- Use multi-stage builds
- Properly configure .dockerignore
- Build with —no-cache when dependency changes
TypeScript-Specific Errors
Section titled “TypeScript-Specific Errors””Cannot use namespace ‘X’ as a value”
Section titled “”Cannot use namespace ‘X’ as a value””Cause: Type-only import used where value needed
Solution:
// Change from:import type { CreateUserCommand } from './commands.js';
// To:import { CreateUserCommand } from './commands.js';“Property ‘X’ does not exist on type ‘Y’”
Section titled ““Property ‘X’ does not exist on type ‘Y’””Cause: Type mismatch or incorrect type definition
Solution:
- Check type definitions match usage
- Verify platform package versions match
- Run
pnpm installto update types
”Cannot find module ‘X’ or its corresponding type declarations”
Section titled “”Cannot find module ‘X’ or its corresponding type declarations””Cause: Missing package or type definitions
Solution:
- Install missing package:
pnpm add X - Install types:
pnpm add -D @types/X - Add
.jsextension if relative import
Docker Build Errors
Section titled “Docker Build Errors””Cannot find package @banyanai/platform-*”
Section titled “”Cannot find package @banyanai/platform-*””Cause: Missing authentication token or wrong registry
Solution:
# Ensure .npmrc copied before installCOPY .npmrc ./
# Build with tokenNODE_AUTH_TOKEN=$NODE_AUTH_TOKEN docker compose build my-service“ENOENT: no such file or directory”
Section titled ““ENOENT: no such file or directory””Cause: Missing source files or wrong COPY path
Solution:
# Verify paths in DockerfileCOPY package.json pnpm-lock.yaml ./ # CorrectCOPY src ./src # Ensure src/ exists“node:internal/modules/esm/resolve: Module not found”
Section titled ““node:internal/modules/esm/resolve: Module not found””Cause: Missing .js extension or wrong module resolution
Solution:
- Add .js extensions to imports
- Verify package.json has
"type": "module" - Check tsconfig.json module settings
Build Verification Steps
Section titled “Build Verification Steps”After fixing build issues:
1. Local Build Succeeds
Section titled “1. Local Build Succeeds”# Clean buildrm -rf dist/pnpm run build
# Should complete without errors# Check outputls dist/
# Should see compiled JavaScript files2. Type Check Passes
Section titled “2. Type Check Passes”pnpm run type-check
# Should show no errors3. Docker Build Succeeds
Section titled “3. Docker Build Succeeds”docker compose build my-service
# Should complete successfully# Check image createddocker images | grep my-service4. Service Starts
Section titled “4. Service Starts”docker compose up my-service
# Should start without errors# Check logsdocker logs my-serviceCommon Build Commands
Section titled “Common Build Commands”# Clean buildrm -rf dist/ && pnpm run build
# Build with loggingpnpm run build 2>&1 | tee build.log
# Type check onlypnpm run type-check
# Build all packages (monorepo)pnpm -r run build
# Build specific packagecd platform/packages/cqrs && pnpm run build
# Docker build (no cache)docker compose build --no-cache my-service
# Docker build with specific targetdocker build --target builder -t my-service:build .Prevention Checklist
Section titled “Prevention Checklist”Before committing, verify:
- All imports have
.jsextension - All platform packages at same version
- Value imports for decorator arguments
- tsconfig.json has required settings
- package.json includes all dependencies
- .dockerignore excludes node_modules
- .npmrc configured with authentication
- NODE_AUTH_TOKEN set for Docker builds
- Type check passes:
pnpm run type-check - Build succeeds:
pnpm run build - Docker build succeeds
Debugging Build Errors
Section titled “Debugging Build Errors”Enable Verbose TypeScript Output
Section titled “Enable Verbose TypeScript Output”# Build with verbose loggingnpx tsc --noEmit --listFiles --pretty
# Shows all files being compiledCheck Module Resolution
Section titled “Check Module Resolution”# Trace module resolutionnpx tsc --noEmit --traceResolution > resolution.log
# Review resolution.log for import failuresgrep "Module not found" resolution.logInspect Docker Build Layers
Section titled “Inspect Docker Build Layers”# Build with progress outputDOCKER_BUILDKIT=1 docker build --progress=plain .
# Shows each layer and command outputTest in Isolation
Section titled “Test in Isolation”# Test single file compilationnpx tsc src/commands/CreateUserHandler.ts --noEmit
# Identifies file-specific errorsRelated Documentation
Section titled “Related Documentation”- Development Workflow - Build and development process
- Service Won’t Start - Runtime startup errors
- TypeScript Setup - TypeScript configuration
- Docker Setup - Docker best practices
Summary
Section titled “Summary”Most build failures are caused by:
- Missing
.jsextensions - Add to all relative imports - Package version mismatch - Keep all platform packages at same version
- Type-only imports for decorators - Use value imports instead
- Missing TypeScript config - Ensure experimentalDecorators enabled
- Docker cache issues - Build with —no-cache
Always check build logs for specific error messages and fix systematically from first error to last.