{"record":{"id":"63338372ea0bc11e","repo":"coleam00/Archon","slug":"pi-sdk-module-modulefile-has-no-export-exp","errorCode":null,"errorMessage":"Pi SDK module '${moduleFile}' has no export '${exportName}'.","messagePattern":"Pi SDK module '(.+?)' has no export '(.+?)'\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/providers/src/oauth.ts","lineNumber":64,"sourceCode":"const oauthAuthCache = new Map<string, OAuthAuth>();\n\nasync function loadOAuthAuth(moduleFile: string, exportName: string): Promise<OAuthAuth> {\n  const cached = oauthAuthCache.get(moduleFile);\n  if (cached) return cached;\n  const { createRequire } = await import('node:module');\n  const { fileURLToPath } = await import('node:url');\n  // Called through the module object: node:path types dirname/join as\n  // PlatformPath methods, so destructuring them trips eslint unbound-method.\n  const path = await import('node:path');\n  // fileURLToPath returns backslash-separated paths on Windows — build the\n  // deep path with node:path, never string concatenation on '/'.\n  const sdkPkgPath = fileURLToPath(import.meta.resolve('@earendil-works/pi-ai/package.json'));\n  const deepPath = path.join(path.dirname(sdkPkgPath), 'dist', 'auth', 'oauth', moduleFile);\n  const require = createRequire(import.meta.url);\n  const mod = require(deepPath) as Record<string, OAuthAuth>;\n  const oauthAuth = mod[exportName];\n  if (!oauthAuth) {\n    throw new Error(`Pi SDK module '${moduleFile}' has no export '${exportName}'.`);\n  }\n  oauthAuthCache.set(moduleFile, oauthAuth);\n  return oauthAuth;\n}\n\n/* ─── Legacy surface preserved for `@archon/core` consumers ───────────────── */\n\n/** Subset of the pre-0.84 callback-driven login surface the bridge relies on. */\nexport interface OAuthLoginCallbacks {\n  onAuth(info: { url: string; instructions?: string }): void;\n  onDeviceCode(info: { userCode: string; verificationUri: string }): void;\n  onManualCodeInput?(): Promise<string>;\n  onPrompt(prompt: unknown): Promise<string>;\n  onSelect(prompt: {\n    options: readonly { id: string; label?: string }[];\n  }): Promise<string | undefined>;\n  onProgress?(message: string): void;\n  signal?: AbortSignal;","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/coleam00/Archon/blob/0773b9745896ef0612e709c80845a0f7db315b19/packages/providers/src/oauth.ts#L46-L82","documentation":"loadOAuthAuth resolves a deep module ('dist/auth/oauth/<moduleFile>') inside the installed @earendil-works/pi-ai SDK and reads the named export, which must be an OAuthAuth implementation. The throw means the module loaded but did not export the expected symbol — almost always because the installed SDK version has a different internal auth module layout or export name than the provider adapter expects. The cache is only populated after a successful lookup, so the failure repeats on every call.","triggerScenarios":"anthropicOAuthProvider or githubCopilotOAuthProvider calls loadOAuthAuth(moduleFile, exportName) and require(deepPath) returns an object without the exportName key (e.g. SDK upgraded/renamed its 'dist/auth/oauth/*.js' files, or a wrong/partial install resolves a stale copy).","commonSituations":"Pi SDK version drift after a dependency bump; a lockfile pinning an older/newer pi-ai whose internal oauth module files moved; monorepo hoisting resolving a different pi-ai copy than intended; upstream SDK refactors renaming exports without a semver major.","solutions":["Check the installed @earendil-works/pi-ai version and inspect dist/auth/oauth/ to confirm the module file and export name still exist","Pin or bump the pi-ai dependency to the version the provider adapter was built against (update package.json/lockfile and reinstall)","Regenerate/update the moduleFile/exportName mapping in packages/providers/src/oauth.ts to match the installed SDK","Clear node_modules and reinstall to rule out a corrupted or duplicated hoisted copy"],"exampleFix":"// before (SDK renamed the export)\nloadOAuthAuth('anthropic.js', 'anthropicOAuth');\n// after (match the installed SDK's actual export)\nloadOAuthAuth('anthropic.js', 'anthropic');","handlingStrategy":"validation","validationCode":"import { createRequire } from 'node:module';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nconst sdkPkgPath = fileURLToPath(import.meta.resolve('@earendil-works/pi-ai/package.json'));\nconst deepPath = path.join(path.dirname(sdkPkgPath), 'dist', 'auth', 'oauth', moduleFile);\nconst mod = createRequire(import.meta.url)(deepPath);\nif (typeof mod?.[exportName] !== 'function') {\n  throw new Error(`pi-ai ${moduleFile} missing export ${exportName}; check installed version`);\n}","typeGuard":"function hasOAuthExport(mod: Record<string, unknown>, name: string): mod is Record<string, OAuthAuth> {\n  return typeof mod[name] === 'function';\n}","tryCatchPattern":"try {\n  oauthAuth = loadOAuthAuth(moduleFile, exportName);\n} catch (err) {\n  console.error(`SDK/adapter mismatch for ${moduleFile}.${exportName}; verify pi-ai version`, err);\n  throw err;\n}","preventionTips":["Pin the pi-ai dependency version alongside the adapter code","Add a startup smoke test that resolves every oauth module/export the adapters need","Re-run provider auth tests after any dependency bump"],"tags":["oauth","sdk-version-mismatch","providers"],"backgroundTag":"sdk-export-not-found","analyzedSha":"0773b9745896ef0612e709c80845a0f7db315b19","analyzedAt":"2026-09-01T02:28:07.064Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}