ruvnet/ruflo · error · Error

module loaded but is missing expected OAuth exports

Error message

module loaded but is missing expected OAuth exports

What it means

Internal guard inside loadSecurityOAuth(). Fires when the dynamic import('@claude-flow/security') resolved successfully (the package IS installed and resolvable) but the resulting module object lacks the expected authorizeUrl or createKeychainAdapter exports. This signals a version mismatch or package shadowing. The bare Error thrown here is immediately caught by the surrounding try/catch and re-wrapped as SecurityPackageMissingError (error 162), so end users normally see 162's message — 161 only surfaces if you inspect the cause chain.

Source

Thrown at v3/@claude-flow/cli/src/auth/security-bridge.ts:70

      "ruflo auth needs the '@claude-flow/security' package, which isn't installed " +
        "(it's an optional dependency — install/reinstall failed or was skipped for this " +
        `platform). Try: npm install @claude-flow/security. Underlying error: ${
          cause instanceof Error ? cause.message : String(cause)
        }`,
    );
    this.name = 'SecurityPackageMissingError';
  }
}

let cached: SecurityOAuthModule | null = null;

/** Loads `@claude-flow/security`'s OAuth surface, throwing a clear error if it's absent. */
export async function loadSecurityOAuth(): Promise<SecurityOAuthModule> {
  if (cached) return cached;
  try {
    const mod = (await import('@claude-flow/security')) as unknown as SecurityOAuthModule;
    if (!mod.authorizeUrl || !mod.createKeychainAdapter) {
      throw new Error('module loaded but is missing expected OAuth exports');
    }
    cached = mod;
    return mod;
  } catch (e) {
    throw new SecurityPackageMissingError(e);
  }
}

View on GitHub (pinned to 6b01dc5a68)

Solutions

  1. Verify the resolved version: run `npm ls @claude-flow/security` and confirm it matches what the CLI expects
  2. Upgrade to the latest: `npm install @claude-flow/security@latest`
  3. Clear the lockfile and node_modules, then reinstall to resolve hoisting shadowing in a monorepo
  4. Check package.json for `overrides` (npm) or `resolutions` (yarn) that redirect @claude-flow/security to a fork

Example fix

// before: stale lockfile resolves an old security package without createKeychainAdapter
// package-lock.json pins @claude-flow/security@0.1.0

// after:
// npm install @claude-flow/security@latest
// now loadSecurityOAuth() finds both authorizeUrl and createKeychainAdapter exports
Defensive patterns

Strategy: try-catch

Type guard

import type { SecurityOAuthModule } from '@claude-flow/cli/auth/security-bridge';

async function isSecurityModuleUsable(): Promise<boolean> {
  try {
    const mod = await import('@claude-flow/security');
    return typeof (mod as any).authorizeUrl === 'function'
        && typeof (mod as any).createKeychainAdapter === 'function';
  } catch {
    return false;
  }
}

Try / catch

import { loadSecurityOAuth, SecurityPackageMissingError } from '@claude-flow/cli/auth/security-bridge';

try {
  const sec = await loadSecurityOAuth();
  // use sec.authorizeUrl(...)
} catch (e) {
  if (e instanceof SecurityPackageMissingError) {
    console.error(e.message); // includes the underlying cause + install command
    process.exit(1);
  }
  throw e;
}

Prevention

When it happens

Trigger: loadSecurityOAuth() is called (by any ruflo auth path, browserLogin, manualLogin, tokenStdinLogin, or refreshAccessToken) and import('@claude-flow/security') resolves to a module whose authorizeUrl or createKeychainAdapter property is falsy.

Common situations: A stale lockfile pins an old @claude-flow/security that predates the createKeychainAdapter export; a monorepo hoisting resolves a workspace-local stub or fork; an `overrides`/`resolutions` field in package.json redirects the package name to an incompatible implementation; a partial publish left the package with missing entry points.

Related errors


AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12). Data as JSON: /api/errors/c094f2101b2476fd. Report an issue: GitHub.