{"record":{"id":"d3d602d142cccb8e","repo":"can1357/oh-my-pi","slug":"invalid-sql-identifier-name","errorCode":null,"errorMessage":"Invalid SQL identifier: ${name}","messagePattern":"Invalid SQL identifier: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/mnemopi/src/core/binary-vectors.ts","lineNumber":60,"sourceCode":"}\n\ninterface VectorRow {\n\tmemory_id: string;\n\tbinary_vector: Uint8Array | ArrayBuffer | Buffer;\n\toriginal_dim: number | null;\n\tmagnitude: number | null;\n}\n\ninterface StatsRow {\n\tcount: number;\n\tavg_bytes: number | null;\n\tmax_bytes: number | null;\n\tmin_bytes: number | null;\n}\n\nfunction assertSqlIdentifier(name: string): string {\n\tif (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) {\n\t\tthrow new Error(`Invalid SQL identifier: ${name}`);\n\t}\n\treturn name;\n}\n\nfunction toFiniteNumber(value: number | string | boolean | null | undefined): number {\n\tconst n = Number(value ?? 0);\n\treturn Number.isFinite(n) ? n : 0;\n}\n\nfunction magnitude(embedding: readonly number[]): number {\n\tlet sum = 0;\n\tfor (let i = 0; i < embedding.length; i += 1) {\n\t\tconst value = toFiniteNumber(embedding[i]);\n\t\tsum += value * value;\n\t}\n\treturn Math.sqrt(sum);\n}\n","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/mnemopi/src/core/binary-vectors.ts#L42-L78","documentation":"assertSqlIdentifier checks that a name (table or column used in dynamic SQL) matches `/^[A-Za-z_][A-Za-z0-9_]*$/` before interpolation, throwing a generic Error otherwise. This is a SQL-injection / query-construction guard in BinaryVectorStore's constructor, not a data validator.","triggerScenarios":"Constructing the binary-vectors store with a table name containing dashes, dots, spaces, quotes, or starting with a digit — anything interpolated into SQL as an identifier.","commonSituations":"Deriving table names from user input or file names (e.g. `my-table`, `2024_logs`), or passing namespaced names like `schema.table`.","solutions":["Rename the table to snake_case matching `[A-Za-z_][A-Za-z0-9_]*` (letters/digits/underscore, not starting with a digit).","Sanitize/derive the name programmatically: replace invalid chars with underscores and prefix if it starts with a digit.","If you need schema-qualified or quoted names, this API does not support them — keep to simple identifiers."],"exampleFix":"// before\nnew BinaryVectorStore(db, { table: \"2024-embeddings\" });\n// after\nnew BinaryVectorStore(db, { table: \"embeddings_2024\" });","handlingStrategy":"validation","validationCode":"const IDENT_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;\nif (!IDENT_RE.test(table)) throw new Error(`Table name must match [A-Za-z_][A-Za-z0-9_]*: ${table}`);","typeGuard":"function isSqlIdentifier(s: string): boolean {\n  return /^[A-Za-z_][A-Za-z0-9_]*$/.test(s);\n}","tryCatchPattern":"try {\n  store = new BinaryVectorStore(db, { table });\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith(\"Invalid SQL identifier\")) {\n    store = new BinaryVectorStore(db, { table: table.replace(/[^A-Za-z0-9_]/g, \"_\").replace(/^\\d/, \"t$&\") });\n  } else throw e;\n}","preventionTips":["Never build table names from raw user input or file names.","Enforce a snake_case naming convention for dynamic SQL identifiers.","Validate identifiers once at config-load time, before any store construction."],"tags":["sql","injection","validation","identifier"],"backgroundTag":"invalid-sql-identifier","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}