can1357/oh-my-pi · error · Error

No active stack frame. Run stack_trace first or supply frame

Error message

No active stack frame. Run stack_trace first or supply frame_id.

What it means

DapSessionManager.scopes needs a stack frame id to request variable scopes from the adapter. It resolves frameId from the argument or from the session's last recorded stop (set by stack_trace). If neither exists — the session never stopped or stack_trace was never run — there is no frame to query, so it throws.

Source

Thrown at packages/coding-agent/src/dap/session.ts:1067

				...(frameCount !== undefined ? { levels: frameCount } : {}),
			} satisfies DapStackTraceArguments,
			signal,
			timeoutMs,
		);
		session.lastStackFrames = response?.stackFrames ?? [];
		this.#applyTopFrame(session, session.lastStackFrames[0]);
		return {
			snapshot: buildSummary(session),
			stackFrames: session.lastStackFrames,
			totalFrames: response?.totalFrames,
		};
	}

	async scopes(frameId: number | undefined, signal?: AbortSignal, timeoutMs: number = 30_000) {
		const session = this.#touchActiveSession();
		const resolvedFrameId = frameId ?? session.stop.frameId;
		if (resolvedFrameId === undefined) {
			throw new Error("No active stack frame. Run stack_trace first or supply frame_id.");
		}
		const response = await this.#sendRequestWithConfig<DapScopesResponse>(
			session,
			"scopes",
			{ frameId: resolvedFrameId } satisfies DapScopesArguments,
			signal,
			timeoutMs,
		);
		return { snapshot: buildSummary(session), scopes: response?.scopes ?? [] };
	}

	async variables(variableReference: number, signal?: AbortSignal, timeoutMs: number = 30_000) {
		const session = this.#touchActiveSession();
		const response = await this.#sendRequestWithConfig<DapVariablesResponse>(
			session,
			"variables",
			{ variablesReference: variableReference } satisfies DapVariablesArguments,
			signal,

View on GitHub (pinned to 9690622007)

Solutions

  1. Run the stack_trace tool/request first so the session records a stop frame, then call scopes()
  2. Pass an explicit numeric frameId obtained from a previous stack_trace response
  3. Only call scopes() while the debuggee is stopped (after a stopped event); check session status first
  4. If the program resumed, break again before querying scopes

Example fix

// before
const scopes = await manager.scopes(undefined); // no stop recorded
// after
const trace = await manager.stackTrace(undefined);
const frameId = trace.stackFrames[0]?.id;
if (frameId === undefined) throw new Error('debuggee not stopped');
const scopes = await manager.scopes(frameId);
Defensive patterns

Strategy: validation

Validate before calling

const active = session.status === 'stopped' ? session.stop?.frameId : undefined;
if (active === undefined) {
  await manager.stackTrace(); // record the stop frame first
}

Type guard

function hasActiveFrame(session: DapSession): session is DapSession & { stop: { frameId: number } } {
  return typeof session.stop?.frameId === 'number';
}

Try / catch

try {
  return await manager.scopes(frameId);
} catch (err) {
  if (String((err as Error).message).includes('No active stack frame')) {
    await manager.stackTrace();
    return await manager.scopes(undefined); // retry with recorded frame
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling scopes() on a session that has not hit a breakpoint/stop and without a frameId argument; calling scopes() after the stop state was cleared (resumed/terminated); passing frameId: undefined explicitly while no stack trace was captured.

Common situations: Tool flow calls scopes before running stack_trace; evaluating scopes after the program resumed so stop.frameId was invalidated; session attached but program running (no stop events yet); new session created without any stop recorded.

Related errors


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