{"record":{"id":"0530474589f13a5e","repo":"n8n-io/n8n","slug":"invalid-pgvectorstore-table-name-string-this-ta","errorCode":null,"errorMessage":"Invalid PgVectorStore table name \"${String(this.tableName)}\": must match ${IDENTIFIER_PATTERN}","messagePattern":"Invalid PgVectorStore table name \"(.+?)\": must match (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/@n8n/agents/src/vector-stores/postgres.ts","lineNumber":58,"sourceCode":" * ```typescript\n * const store = new PgVectorStore('product-docs', {\n *   connectionString: 'postgresql://user:pass@localhost:5432/db',\n *   tableName: 'product_docs',\n * });\n * ```\n */\nexport class PgVectorStore extends BaseVectorStore<PgVectorStoreOptions> {\n\tprivate readonly tableName: string;\n\n\tprivate pool?: Pool;\n\n\tprivate iterativeScanSupportedPromise?: Promise<boolean>;\n\n\tconstructor(name: string, options: PgVectorStoreOptions) {\n\t\tsuper(name, options);\n\t\tthis.tableName = options.tableName;\n\t\tif (typeof this.tableName !== 'string' || !IDENTIFIER_PATTERN.test(this.tableName)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid PgVectorStore table name \"${String(this.tableName)}\": must match ${IDENTIFIER_PATTERN}`,\n\t\t\t);\n\t\t}\n\t}\n\n\tasync upsert(records: VectorRecord[]): Promise<void> {\n\t\tif (records.length === 0) return;\n\n\t\tconst pool = await this.getPool();\n\t\tconst values: string[] = [];\n\t\tconst params: unknown[] = [];\n\t\trecords.forEach((record, index) => {\n\t\t\tconst base = index * 4;\n\t\t\tvalues.push(`($${base + 1}, $${base + 2}, $${base + 3}, $${base + 4}::vector)`);\n\t\t\tparams.push(\n\t\t\t\trecord.id,\n\t\t\t\trecord.content,\n\t\t\t\tJSON.stringify(record.metadata),","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/agents/src/vector-stores/postgres.ts#L40-L76","documentation":"Thrown in the PgVectorStore constructor when tableName fails the IDENTIFIER_PATTERN `/^[A-Za-z_][A-Za-z0-9_]*$/`. The table name is interpolated directly into SQL (it cannot be a bind parameter), so it is locked to a safe identifier grammar to prevent SQL injection and syntax errors. Schema-qualified names, dots, hyphens, spaces, digits-first, and quoted identifiers all fail. This throws at construction time, before any DB connection.","triggerScenarios":"Passing `tableName: 'public.product_docs'` (dot), `'product-docs'` (hyphen), `'2docs'` (digit-first), `'Product Docs'` (space/uppercase+space — uppercase alone is allowed but space is not), `'\"docs\"'` (quotes), or an empty string.","commonSituations":"Using a schema-qualified Postgres table name; copying a table name with hyphens from a separate DB tool; environment/config injection of an unvalidated table name; multi-tenant setups wanting `tenant_123.docs`.","solutions":["Pass a bare identifier matching the pattern: letters/underscore start, then letters/digits/underscore (e.g. `product_docs`).","If your table is in a non-public schema, connect with a role/search_path that defaults to that schema and pass only the table name.","Rename the Postgres table to a valid identifier if you control the schema.","Validate the table name from config with the same regex before constructing the store."],"exampleFix":"// before\nnew PgVectorStore('docs', { connectionString, tableName: 'public.product-docs' });\n\n// after\nnew PgVectorStore('docs', { connectionString, tableName: 'product_docs' });","handlingStrategy":"validation","validationCode":"const IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;\n\nfunction assertValidTableName(name: unknown): string {\n  if (typeof name !== 'string' || !IDENTIFIER_PATTERN.test(name)) {\n    throw new Error(`Invalid table name \"${String(name)}\": must match ${IDENTIFIER_PATTERN}`);\n  }\n  return name;\n}\n\nnew PgVectorStore('docs', { connectionString, tableName: assertValidTableName(process.env.PG_TABLE) });","typeGuard":"function isValidPgIdentifier(name: string): boolean {\n  return /^[A-Za-z_][A-Za-z0-9_]*$/.test(name);\n}\n\nif (!isValidPgIdentifier(config.table)) throw new Error('Bad table name');","tryCatchPattern":null,"preventionTips":["Keep Postgres table names as bare identifiers: letters/underscore start, then letters/digits/underscore.","Don't schema-qualify at the store layer — set the role/search_path instead.","Validate config-provided table names with the same regex before constructing the store."],"tags":["postgres","validation","configuration","sql-injection-safety"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}