can1357/oh-my-pi · error · Error

options.authStorage and options.modelRegistry.authStorage mu

Error message

options.authStorage and options.modelRegistry.authStorage must be the same instance when both are provided

What it means

When constructing the executor, if the caller supplies both options.authStorage and options.modelRegistry, the code derives authStorage from modelRegistry and verifies identity. Passing two different AuthStorage instances is ambiguous (two sources of truth for credentials), so it throws.

Source

Thrown at packages/coding-agent/src/task/executor.ts:2975

		// Launch-latency phase marks (performance.now()); read by the debug log
		// emitted before this closure returns. Left undefined when setup throws
		// before reaching the phase, which itself localizes the cost.
		const perfStart = performance.now();
		let resolvedAt: number | undefined;
		let sessionOpenedAt: number | undefined;
		let sessionCreatedAt: number | undefined;
		let readyAt: number | undefined;

		try {
			checkAbort();
			// Pin authStorage to modelRegistry.authStorage — mirrors the createAgentSession invariant.
			const registryFromParent = options.modelRegistry !== undefined;
			const modelRegistry =
				options.modelRegistry ??
				new ModelRegistry(options.authStorage ?? (await awaitAbortable(discoverAuthStorage())));
			const authStorage = modelRegistry.authStorage;
			if (options.authStorage && options.authStorage !== authStorage) {
				throw new Error(
					"options.authStorage and options.modelRegistry.authStorage must be the same instance when both are provided",
				);
			}
			checkAbort();
			if (!registryFromParent) {
				modelRegistry.refreshInBackground();
			} else {
				logger.debug("runSubagent: reusing parent modelRegistry; skipping refresh");
			}
			checkAbort();

			const configuredModelPatterns = resolveConfiguredModelPatterns(modelPatterns, settings);
			const inheritedRetryFallbackChain =
				configuredModelPatterns.length === 1
					? resolveSubagentInheritedRetryFallbackChain(
							subagentSettings,
							modelRegistry,
							modelRole ?? resolveExplicitModelRole(modelPatterns, subagentSettings),

View on GitHub (pinned to 9690622007)

Solutions

  1. Pass only options.modelRegistry built with your AuthStorage: new ModelRegistry(authStorage), and omit options.authStorage.
  2. Or pass only options.authStorage and let the executor create the ModelRegistry.
  3. If both must be passed, ensure they are the same instance: registry.authStorage === authStorage.
  4. Audit instance caching — avoid constructing a fresh AuthStorage after the registry was already built.

Example fix

// before
new Executor({ authStorage: myAuth, modelRegistry: new ModelRegistry(discoverAuthStorage()) })
// after
new Executor({ modelRegistry: new ModelRegistry(myAuth) })
Defensive patterns

Strategy: validation

Validate before calling

function assertConsistentAuth(opts: { authStorage?: AuthStorage; modelRegistry?: ModelRegistry }): void {
  if (opts.authStorage && opts.modelRegistry && opts.modelRegistry.authStorage !== opts.authStorage) {
    throw new Error("authStorage must be modelRegistry.authStorage when both are passed");
  }
}

Try / catch

try {
  const executor = new Executor(options);
} catch (err) {
  if (String(err.message).includes("must be the same instance")) {
    // rebuild with a single source of truth
    return new Executor({ modelRegistry: new ModelRegistry(options.authStorage) });
  }
  throw err;
}

Prevention

When it happens

Trigger: Creating the task executor with options = { authStorage: instanceA, modelRegistry: registryB } where registryB.authStorage !== instanceA — the mismatch check `options.authStorage && options.authStorage !== authStorage` fires.

Common situations: Embedding the SDK and constructing a ModelRegistry with its own discovered auth storage while separately passing a custom AuthStorage, wiring two different profile directories, or caching instances across config reloads so one became stale.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/feb14ea20b2b877f. Report an issue: GitHub.