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
- Pass the adapter explicitly: new SqlSessionStorage({ client, adapter: 'postgres' | 'mysql' | 'sqlite' }).
- If relying on inference, ensure the client object exposes options.adapter with a recognized value ('postgres', 'postgresql', 'pg', 'mysql', 'mariadb', 'sqlite', 'sqlite3').
- Check for typos/case — detection lowercases, but the spelling must match exactly.
- 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
- Always pass `adapter` explicitly instead of relying on inference.
- Centralize the adapter value in one config constant.
- Validate driver config at startup with a fail-fast check.
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
- OMP_AUTH_BROKER_ACCOUNT_POOL_FILE contains an empty provider
- OMP_AUTH_BROKER_ACCOUNT_POOL_FILE contains a provider id wit
- ${name} path does not exist: ${trimmed}
- Anthropic thinking budget requires max_tokens greater than $
- cachedContent must not be blank
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/accd323c32a15e63.
Report an issue: GitHub.