can1357/oh-my-pi · error · Error

Cannot export in-memory session to HTML

Error message

Cannot export in-memory session to HTML

What it means

exportSessionToHtml renders a session to HTML from a SessionManager. Export requires a persisted session file to read (and to collect sub-sessions from); when the SessionManager was created purely in memory (no backing session file), getSessionFile() returns null and this error is thrown. It guards against exporting data that was never written to disk.

Source

Thrown at packages/coding-agent/src/export/html/index.ts:276

	const sessionDataBase64 = Buffer.from(JSON.stringify(sessionData)).toBase64();

	// Use function replacements so `$'`, `$&`, `$$`, `$n`, etc. in the
	// substituted CSS/base64 are not interpreted as substitution patterns.
	return getTemplate()
		.replace("<theme-vars/>", () => `<style>${themeStyles}</style>`)
		.replace("{{SESSION_DATA}}", () => sessionDataBase64);
}

/** Export session to HTML using SessionManager and AgentState. */
export async function exportSessionToHtml(
	sm: SessionManager,
	state?: AgentState,
	options?: ExportOptions | string,
): Promise<string> {
	const opts: ExportOptions = typeof options === "string" ? { outputPath: options } : options || {};

	const sessionFile = sm.getSessionFile();
	if (!sessionFile) throw new Error("Cannot export in-memory session to HTML");

	const sessionData = buildSessionData(sm, state);
	if (opts.includeSubSessions !== false) {
		const subSessions = await collectSubSessions(sessionFile);
		if (Object.keys(subSessions).length > 0) sessionData.subSessions = subSessions;
	}

	const palette = opts.palette ?? (opts.themeName ? "theme" : "web");
	const html = await generateHtml(sessionData, palette, opts.themeNames, opts.themeName);
	const outputPath = opts.outputPath || `${APP_NAME}-session-${path.basename(sessionFile, ".jsonl")}.html`;

	await Bun.write(outputPath, html);
	return outputPath;
}

/** Export session file to HTML (standalone). */
export async function exportFromFile(inputPath: string, options?: ExportOptions | string): Promise<string> {
	const opts: ExportOptions = typeof options === "string" ? { outputPath: options } : options || {};

View on GitHub (pinned to 9690622007)

Solutions

  1. Persist the session first — ensure SessionManager was opened with a real session file path.
  2. For in-memory sessions, serialize entries yourself and render via a lower-level HTML builder, or write a session file then export.
  3. Check sm.getSessionFile() before calling and branch to an alternate export path when null.

Example fix

// before
await exportToHtml(sessionManager); // in-memory session
// after
if (!sessionManager.getSessionFile()) {
  throw new Error("Persist the session before exporting");
}
await exportToHtml(sessionManager);
Defensive patterns

Strategy: validation

Validate before calling

if (!sm.getSessionFile()) {
  throw new Error("Session has no backing file; persist it before exporting to HTML");
}
await exportToHtml(sm);

Type guard

function isExportable(sm: SessionManager): boolean {
  return typeof sm.getSessionFile() === "string";
}

Try / catch

try {
  return await exportToHtml(sm);
} catch (err) {
  if (err instanceof Error && err.message.includes("in-memory session")) {
    throw new Error("Open the session from a file (SessionManager.open) before exporting");
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling exportSessionToHtml(sm, ...) (directly or via exportToHtml) on a SessionManager opened without a file / created programmatically, so sm.getSessionFile() returns undefined.

Common situations: SDK embedding that constructs a SessionManager in memory for a scripted agent run and then tries to export the transcript; tests creating ephemeral sessions; calling export before the session was ever persisted.

Related errors


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