can1357/oh-my-pi · error
SqlSessionStorage: table name must match ${IDENT_RE.source}
Error message
SqlSessionStorage: table name must match ${IDENT_RE.source} (got ${JSON.stringify(table)}) What it means
SqlSessionStorage interpolates the table name directly into generated SQL, so it validates it against IDENT_RE (identifier-safe characters only) in the constructor and throws if it fails. This prevents SQL injection and syntax errors from table names containing quotes, dashes, spaces, or dots.
Source
Thrown at packages/coding-agent/src/session/sql-session-storage.ts:278
get table(): string {
return this.#table;
}
}
class SqlSessionStorageBackend implements SessionStorageBackend {
readonly #client: SqlSessionStorageClient;
readonly #adapter: SqlSessionStorageAdapter;
readonly #table: string;
readonly #q: DialectQueries;
readonly #createTable: boolean;
constructor(options: SqlSessionStorageOptions) {
this.#client = options.client;
this.#adapter = options.adapter ?? detectAdapter(options.client);
const table = options.table ?? DEFAULT_TABLE;
if (!IDENT_RE.test(table)) {
throw new Error(`SqlSessionStorage: table name must match ${IDENT_RE.source} (got ${JSON.stringify(table)})`);
}
this.#table = table;
this.#q = buildQueries(this.#adapter, table);
this.#createTable = options.createTable !== false;
}
get adapter(): SqlSessionStorageAdapter {
return this.#adapter;
}
get table(): string {
return this.#table;
}
async init(): Promise<void> {
if (this.#createTable) {
await this.#client.unsafe(this.#q.createTable);
for (const query of this.#q.addTitleColumns) {View on GitHub (pinned to 9690622007)
Solutions
- Use a plain identifier: letters, digits, underscores only, e.g. 'sessions' or 'omp_sessions_v2'.
- Sanitize derived names before passing: replace invalid chars with '_' and ensure it doesn't start with a digit if IDENT_RE requires that.
- Omit the option entirely to use DEFAULT_TABLE.
- If you need schema-qualified names, connect with a search_path/connection default schema instead.
Example fix
// before
new SqlSessionStorage({ client, adapter: 'postgres', table: 'omp.sessions' });
// after
new SqlSessionStorage({ client, adapter: 'postgres', table: 'omp_sessions' }); Defensive patterns
Strategy: validation
Validate before calling
const IDENT_RE = /^[A-Za-z_][A-Za-z0-9_]*$/; // mirror of the library check
if (!IDENT_RE.test(tableName)) {
throw new Error(`table name must be a plain identifier, got: ${tableName}`);
} Type guard
function isValidTableName(t: string): boolean {
return /^[A-Za-z_][A-Za-z0-9_]*$/.test(t);
} Try / catch
try {
storage = new SqlSessionStorage({ client, adapter, table });
} catch (err) {
if (String(err.message).includes('table name must match')) {
table = tableName.replace(/[^A-Za-z0-9_]/g, '_');
storage = new SqlSessionStorage({ client, adapter, table });
} else throw err;
} Prevention
- Build table names only from [A-Za-z0-9_], starting with a letter or underscore.
- Never pass filenames, tenant IDs, or schema-qualified names directly as the table option.
- Sanitize dynamically derived names before constructing the storage.
When it happens
Trigger: new SqlSessionStorage({ ... , table: '<name>' }) where the name fails IDENT_RE — e.g. contains '-', '.', spaces, quotes, or is empty (sql-session-storage.ts:276-279).
Common situations: Deriving the table name from a filename, environment variable, or tenant ID that contains hyphens or dots ('my-sessions', 'omp.sessions'); copy-pasting a qualified name like 'public.sessions'; an empty-string config value.
Related errors
- SqlSessionStorage: unable to infer adapter from client.optio
- Invalid SQL identifier: ${name}
- Delta table ${String(table)} is not in the allowlist
- Unsupported language '{value}'. Supported: {}
- Unable to infer language from file extension: {}. Specify `l
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/596c9802e7a74859.
Report an issue: GitHub.