Skip to content

fix(postgres): sanitize all non-identifier chars in table names#48

Merged
mudler merged 1 commit into
mainfrom
fix/postgres-collection-colon
Jun 18, 2026
Merged

fix(postgres): sanitize all non-identifier chars in table names#48
mudler merged 1 commit into
mainfrom
fix/postgres-collection-colon

Conversation

@localai-bot

Copy link
Copy Markdown
Collaborator

Problem

sanitizeTableName only replaced -, . and with underscores. Any other character in a collection name leaked into the interpolated CREATE TABLE DDL and produced a SQL syntax error.

This surfaced as mudler/LocalAI#10375: LocalAI namespaces per-user collections as {userID}:{name}. Under legacy API-key auth the userID is the literal legacy-api-key, so an agent's collection name becomes legacy-api-key:<agent>. The : was never sanitized, so:

CREATE TABLE documents_legacy_api_key:LiteraryResearch (...)
ERROR: syntax error at or near ":" (SQLSTATE 42601)

Agents with knowledge base / long-term memory enabled could not create their PostgreSQL collection. (UUID-based user IDs happened to work only because hyphens were in the replace set.)

Fix

Switch sanitizeTableName from a hardcoded denylist to an allowlist: map any character that is not [A-Za-z0-9_] to _. This guarantees a legal unquoted PostgreSQL identifier for any collection name (:, /, @, etc.), while preserving the previous handling of -, . and .

The userID prefix is kept intact, so per-user table isolation on a shared database is preserved - this only makes the existing namespacing scheme PostgreSQL-safe.

Tests

Added rag/engine/sanitize_test.go (Ginkgo, internal package, no DB required):

  • the #10375 regression case (: separator),
  • a sweep asserting any input sanitizes to a valid identifier,
  • a backward-compat assertion for the previously-handled characters.

Red → green confirmed; package builds and vets clean.

sanitizeTableName only replaced '-', '.' and ' ' with underscores, so a
collection name containing other characters leaked into the interpolated
CREATE TABLE statement and produced a SQL syntax error.

LocalAI namespaces per-user collections as "{userID}:{name}". Under legacy
API-key auth the userID is the literal "legacy-api-key", so an agent's
collection became "legacy-api-key:<agent>". The ':' was not sanitized and
PostgreSQL rejected the DDL with "syntax error at or near ':'" (SQLSTATE
42601), preventing agents with knowledge base / long-term memory from
creating their vector collection.

Switch to an allowlist: map any character that is not [A-Za-z0-9_] to an
underscore. This guarantees a legal unquoted identifier for any collection
name (covering ':', '/', '@', etc.) while preserving the previous handling
of '-', '.' and ' '. The userID prefix is kept intact, so per-user table
isolation on a shared database is unaffected.

Fixes mudler/LocalAI#10375

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
@mudler mudler merged commit d0073dd into main Jun 18, 2026
8 of 9 checks passed
mudler added a commit to mudler/LocalAGI that referenced this pull request Jun 18, 2026
#478)

chore: bump localrecall to include PostgreSQL table-name sanitization fix

Pulls mudler/LocalRecall#48, which makes sanitizeTableName allowlist valid
identifier characters so collection names containing ':' (e.g. the per-user
"legacy-api-key:<agent>" namespace used by LocalAI) no longer break
PostgreSQL CREATE TABLE with "syntax error at or near ':'".

Ref: mudler/LocalAI#10375

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
mudler added a commit to mudler/LocalAI that referenced this pull request Jun 18, 2026
…10375) (#10387)

chore: bump localrecall to include PostgreSQL table-name sanitization fix

Pulls mudler/LocalRecall#48, which makes sanitizeTableName allowlist valid
identifier characters so collection names containing ':' (e.g. the per-user
"legacy-api-key:<agent>" namespace) no longer break PostgreSQL CREATE TABLE
with "syntax error at or near ':'".

Fixes #10375

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
Co-authored-by: Ettore Di Giacinto <mudler@localai.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants