can1357/oh-my-pi · error · ExtensionRuntimeNotInitializedError

Extension runtime not initialized. Action methods cannot be

Error message

Extension runtime not initialized. Action methods cannot be called during extension loading.

What it means

ExtensionRuntime starts with throwing stubs for all action methods; the real implementations are swapped in only after the extension loading/initialization phase completes. Calling sendMessage() on the runtime before initialization (i.e. from code that captured the runtime during extension load) throws this error to make premature use loud and explicit.

Source

Thrown at packages/coding-agent/src/extensibility/extensions/loader.ts:89

/**
 * Extension runtime with throwing stubs for action methods.
 * These are replaced with real implementations during initialization.
 */
export class ExtensionRuntime implements IExtensionRuntime {
	flagValues = new Map<string, boolean | string>();
	pendingProviderRegistrations: Array<{ name: string; config: ProviderConfig; sourceId: string }> = [];

	registerProvider(name: string, config: ProviderConfig, sourceId: string): void {
		this.pendingProviderRegistrations.push({ name, config, sourceId });
	}

	unregisterProvider(name: string): void {
		const remaining = this.pendingProviderRegistrations.filter(registration => registration.name !== name);
		this.pendingProviderRegistrations.splice(0, this.pendingProviderRegistrations.length, ...remaining);
	}

	sendMessage(): void {
		throw new ExtensionRuntimeNotInitializedError();
	}

	sendUserMessage(): void {
		throw new ExtensionRuntimeNotInitializedError();
	}

	appendEntry(): void {
		throw new ExtensionRuntimeNotInitializedError();
	}

	setLabel(): void {
		throw new ExtensionRuntimeNotInitializedError();
	}

	getActiveTools(): string[] {
		throw new ExtensionRuntimeNotInitializedError();
	}

View on GitHub (pinned to 9690622007)

Solutions

  1. Move the sendMessage call into an event handler / lifecycle callback that runs after initialization (e.g. on session start, on command), not at module or factory top level.
  2. Defer via the extension's init/ready hook so the real implementation is installed first.
  3. Verify extension initialization completed (no earlier load errors); if init failed, fix that first.
  4. If you must fire-and-forget, await runtime readiness before calling.

Example fix

// before
export default function (pi) {
  pi.sendMessage('hello'); // throws: runtime not initialized yet
}
// after
export default function (pi) {
  pi.on('session_start', () => pi.sendMessage('hello'));
}
Defensive patterns

Strategy: try-catch

Try / catch

try {
  runtime.sendMessage(text);
} catch (err) {
  if (err instanceof ExtensionRuntimeNotInitializedError) {
    // defer: queue the message and send from a post-init hook/event handler
  } else throw err;
}

Prevention

When it happens

Trigger: An extension's factory or a module-level/top-level hook calls runtime.sendMessage() while extensions are still loading, before the runtime stubs are replaced with the connected implementations.

Common situations: Extension sends a message eagerly at import/factory time instead of inside a handler or on an event; an extension captured the runtime reference and invokes it asynchronously before init finished; initialization failed silently so stubs were never replaced.

Related errors


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