can1357/oh-my-pi · error

SqlSessionStorage: unable to infer adapter from client.optio

Error message

SqlSessionStorage: unable to infer adapter from client.options.adapter=${JSON.stringify(reported)}. Pass an explicit `adapter` option ("postgres" | "mysql" | "sqlite").

What it means

SqlSessionStorage wraps an existing SQL client (e.g. drizzle/kysely-style) and needs to know which SQL dialect to generate queries for. When no explicit `adapter` option is passed, detectAdapter inspects `client.options.adapter` and throws if the reported value isn't one of postgres/mysql/sqlite (aliases like 'pg', 'mariadb', 'sqlite3' accepted). Fail-closed by design: guessing the dialect could produce broken SQL.

Source

Thrown at packages/coding-agent/src/session/sql-session-storage.ts:115

const DEFAULT_TABLE = "omp_session_files";
const IDENT_RE = /^[A-Za-z_][A-Za-z0-9_]{0,62}$/;
const utf8Decoder = new TextDecoder("utf-8");

function enoent(p: string): NodeJS.ErrnoException {
	const err = new Error(`ENOENT: no such file, '${p}'`) as NodeJS.ErrnoException;
	err.code = "ENOENT";
	err.errno = -2;
	err.path = p;
	err.syscall = "open";
	return err;
}

function detectAdapter(client: SqlSessionStorageClient): SqlSessionStorageAdapter {
	const reported = String(client.options?.adapter ?? "").toLowerCase();
	if (reported === "postgres" || reported === "postgresql" || reported === "pg") return "postgres";
	if (reported === "mysql" || reported === "mariadb") return "mysql";
	if (reported === "sqlite" || reported === "sqlite3") return "sqlite";
	throw new Error(
		`SqlSessionStorage: unable to infer adapter from client.options.adapter=${JSON.stringify(reported)}. ` +
			`Pass an explicit \`adapter\` option ("postgres" | "mysql" | "sqlite").`,
	);
}

function buildQueries(adapter: SqlSessionStorageAdapter, table: string): DialectQueries {
	const placeholder = adapter === "postgres" ? (n: number): string => `$${n}` : (_n: number): string => "?";

	if (adapter === "mysql") {
		return {
			createTable:
				`CREATE TABLE IF NOT EXISTS ${table} (` +
				`path VARCHAR(512) NOT NULL PRIMARY KEY, ` +
				`content LONGTEXT NOT NULL, ` +
				`mtime_ms BIGINT NOT NULL, ` +
				`title TEXT NULL, ` +
				`title_source VARCHAR(16) NULL, ` +
				`title_updated_at VARCHAR(64) NULL` +

View on GitHub (pinned to 9690622007)

Solutions

  1. Pass the adapter explicitly: new SqlSessionStorage({ client, adapter: 'postgres' | 'mysql' | 'sqlite' }).
  2. If relying on inference, ensure the client object exposes options.adapter with a recognized value ('postgres', 'postgresql', 'pg', 'mysql', 'mariadb', 'sqlite', 'sqlite3').
  3. Check for typos/case — detection lowercases, but the spelling must match exactly.
  4. Log/inspect JSON.stringify(client.options) to see what the detector actually sees.

Example fix

// before
const storage = new SqlSessionStorage({ client: pgClient });
// after
const storage = new SqlSessionStorage({ client: pgClient, adapter: 'postgres' });
Defensive patterns

Strategy: validation

Validate before calling

const ADAPTERS = new Set(['postgres', 'postgresql', 'pg', 'mysql', 'mariadb', 'sqlite', 'sqlite3']);
if (!ADAPTERS.has(String(client.options?.adapter ?? '').toLowerCase())) {
  throw new Error('pass an explicit adapter option to SqlSessionStorage');
}

Type guard

type KnownAdapter = 'postgres' | 'mysql' | 'sqlite';
function hasKnownAdapter(c: unknown): c is { options: { adapter: KnownAdapter } } {
  const a = (c as { options?: { adapter?: string } })?.options?.adapter;
  return ['postgres', 'mysql', 'sqlite'].includes(String(a).toLowerCase());
}

Try / catch

try {
  storage = new SqlSessionStorage({ client });
} catch (err) {
  if (String(err.message).startsWith('SqlSessionStorage: unable to infer adapter')) {
    storage = new SqlSessionStorage({ client, adapter: detectFromEnv() });
  } else throw err;
}

Prevention

When it happens

Trigger: Constructing SqlSessionStorage with `{ client }` where client.options.adapter is undefined, empty, or an unrecognized string (sql-session-storage.ts:108-117).

Common situations: Passing a raw database driver that doesn't expose an options.adapter field; typo like 'postgresSQL' or 'psql'; using a client library whose adapter config lives somewhere else (e.g. client.config.adapter); forgetting the adapter option after switching client libraries.

Related errors


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