{"record":{"id":"c094f2101b2476fd","repo":"ruvnet/ruflo","slug":"module-loaded-but-is-missing-expected-oauth-export","errorCode":null,"errorMessage":"module loaded but is missing expected OAuth exports","messagePattern":"module loaded but is missing expected OAuth exports","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/auth/security-bridge.ts","lineNumber":70,"sourceCode":"      \"ruflo auth needs the '@claude-flow/security' package, which isn't installed \" +\n        \"(it's an optional dependency — install/reinstall failed or was skipped for this \" +\n        `platform). Try: npm install @claude-flow/security. Underlying error: ${\n          cause instanceof Error ? cause.message : String(cause)\n        }`,\n    );\n    this.name = 'SecurityPackageMissingError';\n  }\n}\n\nlet cached: SecurityOAuthModule | null = null;\n\n/** Loads `@claude-flow/security`'s OAuth surface, throwing a clear error if it's absent. */\nexport async function loadSecurityOAuth(): Promise<SecurityOAuthModule> {\n  if (cached) return cached;\n  try {\n    const mod = (await import('@claude-flow/security')) as unknown as SecurityOAuthModule;\n    if (!mod.authorizeUrl || !mod.createKeychainAdapter) {\n      throw new Error('module loaded but is missing expected OAuth exports');\n    }\n    cached = mod;\n    return mod;\n  } catch (e) {\n    throw new SecurityPackageMissingError(e);\n  }\n}\n","sourceCodeStart":52,"sourceCodeEnd":78,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/cli/src/auth/security-bridge.ts#L52-L78","documentation":"loadSecurityOAuth() dynamically imports @claude-flow/security and probes for authorizeUrl/createKeychainAdapter. If the module resolves but those exports are absent, the install is broken or the resolved version's API doesn't match what the CLI expects (version skew, partial install, a same-named package shadowing it). Note the probe throw happens inside the try, so callers actually receive SecurityPackageMissingError whose underlying message is this string.","triggerScenarios":"An @claude-flow/security version older/newer than the CLI's expected OAuth surface is installed (mixed-version monorepo or pinned old version); node_modules partially written by an interrupted install; a bundler/test mock resolving in place of the real package; a rogue package with the same name earlier on the resolution path.","commonSituations":"npm workspaces/monorepos where a different package pinned an incompatible @claude-flow/security version; `npm install --force` or interrupted installs leaving stub modules; test suites that mock '@claude-flow/security' incompletely (missing authorizeUrl/createKeychainAdapter).","solutions":["Align versions: install the @claude-flow/security version the CLI declares (check @claude-flow/cli's package.json optionalDependencies), e.g. npm install @claude-flow/security@<matching-version>","Clean reinstall: rm -rf node_modules package-lock.json && npm install","Verify what actually resolves: node -e \"import('@claude-flow/security').then(m => console.log(Object.keys(m)))\" — confirm authorizeUrl and createKeychainAdapter are present","Check for duplicate installs / path shadowing: npm ls @claude-flow/security"],"exampleFix":"# before\nnpm install @claude-flow/cli @claude-flow/security@0.9.0   # mismatched versions\n# after\nnpm install @claude-flow/cli && npm install @claude-flow/security@$(node -p \"require('@claude-flow/cli/package.json').optionalDependencies['@claude-flow/security']\")","handlingStrategy":"try-catch","validationCode":"// Pre-flight: confirm the installed security package exposes the OAuth surface\nconst mod = await import('@claude-flow/security');\nif (typeof mod.authorizeUrl !== 'function' || typeof mod.createKeychainAdapter !== 'function') {\n  throw new Error('incompatible @claude-flow/security version — align it with @claude-flow/cli');\n}","typeGuard":"import { SecurityPackageMissingError } from '@claude-flow/cli/dist/auth/security-bridge.js';\nfunction isSecurityPackageProblem(e: unknown): e is SecurityPackageMissingError {\n  return e instanceof Error && e.name === 'SecurityPackageMissingError';\n}","tryCatchPattern":"try {\n  await runAuthCommand();\n} catch (e) {\n  if (isSecurityPackageProblem(e) && e.message.includes('missing expected OAuth exports')) {\n    console.error('Version mismatch: install the @claude-flow/security version declared by @claude-flow/cli');\n    process.exit(5);\n  }\n  throw e;\n}","preventionTips":["Pin @claude-flow/security to the exact version @claude-flow/cli declares in optionalDependencies","Run npm ls @claude-flow/security in CI to detect duplicate/mismatched installs","When mocking the package in tests, stub authorizeUrl and createKeychainAdapter too"],"tags":["auth","dependency","version-mismatch","npm","module-resolution"],"backgroundTag":"package-export-mismatch","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}