Skip to main content

Root Cause Analysis: Undefined Module Export Error

Date: 2025-11-19 Status: ✅ RESOLVED Severity: CRITICAL - Backend start failure

Error Signature

Cannot use 'in' operator to search for '$$type' in undefined
Location: @backstage/backend-app-api/src/wiring/helpers.ts:23:7

Root Cause

The module export is NOT actually undefined. The real issue is a transitive dependency import failure:

Import Chain Analysis

packages/backend/src/index.ts
└─> import('@internal/plugin-terraform-state-backend')
└─> dist/index.cjs.js (exports catalogModuleTerraformStateTfcProvider ✅)
└─> dist/modules/tfcModule.cjs.js ✅
└─> dist/providers/TfcStateProvider.cjs.js ✅
└─> dist/services/VaultTokenService.cjs.js ❌
└─> FAILS: Cannot find module '@internal/backstage-plugin-vault-secrets-backend/src/service/VaultClient'

The Problem

File: plugins/terraform-state-backend/src/services/VaultTokenService.ts:8

// ❌ WRONG: Deep import into package internals
import { VaultClient } from '@internal/backstage-plugin-vault-secrets-backend/src/service/VaultClient';

Issue: The vault plugin does NOT export VaultClient from its package entry point.

Vault Plugin Exports (@internal/backstage-plugin-vault-secrets-backend/src/index.ts):

export { vaultSecretsPlugin as default } from './plugin';
// VaultClient is NOT exported!

Why This Causes "Undefined" Error

  1. Backend tries to load terraform-state-backend module
  2. Module import chain fails at VaultTokenService dependency
  3. The entire module object becomes undefined due to the failed import
  4. Backstage's backend.add() unwrapping function tries to access $$type property
  5. Error: Cannot use 'in' operator to search for '$$type' in undefined

Solution Options

Modify: plugins/backstage-plugin-vault-secrets-backend/src/index.ts

export { vaultSecretsPlugin as default } from './plugin';
export { VaultClient } from './service/VaultClient';
export type { VaultConfig, VaultSecret } from './service/VaultClient';

Then update: plugins/terraform-state-backend/src/services/VaultTokenService.ts

// ✅ CORRECT: Import from package entry point
import { VaultClient } from '@internal/backstage-plugin-vault-secrets-backend';

Option 2: Create Shared Vault Service Package

Create a dedicated package for shared vault utilities that both plugins can depend on.

Duplicate the VaultClient code in terraform-state-backend (violates DRY principle).

Code Quality Issues Identified

1. Deep Imports Anti-Pattern

Severity: HIGH

Using deep imports (package/src/internal/module) is an anti-pattern because:

  • Breaks package encapsulation
  • Couples to internal implementation details
  • Fails when dependencies aren't built or available
  • Makes refactoring difficult

Location: Multiple files in terraform-state-backend

2. Incomplete Package Exports

Severity: MEDIUM

The vault-secrets-backend plugin only exports the plugin itself, not shared utilities.

Impact: Forces consumers to use deep imports or duplicate code

3. Missing Dependency Validation

Severity: MEDIUM

No build-time or runtime validation that required exports are available.

Recommendation: Add TypeScript type checking or runtime validation

Fix Implementation

The fix requires updating both plugins:

  1. Vault Plugin - Export VaultClient
  2. Terraform State Plugin - Update import to use package exports
  3. Both Plugins - Rebuild with yarn build

Prevention

Build-Time Checks

Add to package.json scripts:

{
"scripts": {
"typecheck": "tsc --noEmit",
"prebuild": "yarn typecheck"
}
}

Linting Rules

Add ESLint rule to prevent deep imports:

{
"rules": {
"no-restricted-imports": [
"error",
{
"patterns": ["@internal/*/src/*"]
}
]
}
}
  • /packages/backend/src/index.ts:108 - Backend registration
  • /plugins/terraform-state-backend/src/index.ts - Module export (correct)
  • /plugins/terraform-state-backend/src/modules/tfcModule.ts - Module definition (correct)
  • /plugins/terraform-state-backend/src/services/VaultTokenService.ts:8 - INVALID IMPORT
  • /plugins/backstage-plugin-vault-secrets-backend/src/index.ts - MISSING EXPORT

Status: READY FOR FIX

All analysis complete. Recommended approach: Option 1 (export from vault plugin).


Analysis By: Code Quality Analyzer (Hive Mind) Task ID: task-1763526192977-oajcdxtkg