{"record":{"id":"e1fae2abb4e434d1","repo":"vxcontrol/pentagi","slug":"extension-q-is-installed-in-schema-q-but-multi","errorCode":null,"errorMessage":"extension %q is installed in schema %q, but multi-tenant mode requires it in %q so every tenant can reach it; either run ALTER EXTENSION %s SET SCHEMA %s, or set DATABASE_EXTENSIONS_SCHEMA=%s to match where it already lives","messagePattern":"extension %q is installed in schema %q, but multi-tenant mode requires it in %q so every tenant can reach it; either run ALTER EXTENSION (.+?) SET SCHEMA (.+?), or set DATABASE_EXTENSIONS_SCHEMA=(.+?) to match where it already lives","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/pkg/database/tenant.go","lineNumber":129,"sourceCode":"\tcase schema == \"\":\n\t\t// Not installed yet — create it explicitly in the shared schema.\n\t\tif _, err := conn.ExecContext(ctx, fmt.Sprintf(\n\t\t\t\"CREATE EXTENSION IF NOT EXISTS %s SCHEMA %s\",\n\t\t\tpq.QuoteIdentifier(ext), pq.QuoteIdentifier(sharedSchema),\n\t\t)); err != nil {\n\t\t\treturn fmt.Errorf(\n\t\t\t\t\"failed to create extension %q in schema %q (a privileged user must run \"+\n\t\t\t\t\t\"CREATE EXTENSION %s SCHEMA %s once): %w\",\n\t\t\t\text, sharedSchema, ext, sharedSchema, err,\n\t\t\t)\n\t\t}\n\t\treturn nil\n\n\tcase schema != sharedSchema:\n\t\t// Installed, but somewhere this tenant's search_path will not reach. Fail\n\t\t// with an actionable message rather than letting migrations die on a\n\t\t// confusing \"type does not exist\".\n\t\treturn fmt.Errorf(\n\t\t\t\"extension %q is installed in schema %q, but multi-tenant mode requires it in %q \"+\n\t\t\t\t\"so every tenant can reach it; either run ALTER EXTENSION %s SET SCHEMA %s, \"+\n\t\t\t\t\"or set DATABASE_EXTENSIONS_SCHEMA=%s to match where it already lives\",\n\t\t\text, schema, sharedSchema, ext, sharedSchema, schema,\n\t\t)\n\n\tdefault:\n\t\treturn nil\n\t}\n}\n\n// extensionSchema returns the schema an extension is installed into, or \"\" when\n// it is not installed.\nfunc extensionSchema(ctx context.Context, conn *sql.Conn, ext string) (string, error) {\n\tvar schema string\n\terr := conn.QueryRowContext(ctx, `\n\t\tSELECT n.nspname\n\t\t  FROM pg_extension e","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/database/tenant.go#L111-L147","documentation":"This is a deliberate configuration-consistency error: the extension is installed, but in a schema other than the configured shared extension schema (DATABASE_EXTENSIONS_SCHEMA, default public). In multi-tenant mode every extension must live in one schema reachable from every tenant's search_path, otherwise tenants hit opaque 'type vector does not exist' during migrations. The code fails fast with an actionable remediation message instead.","triggerScenarios":"TENANT_ID is set, pg_extension shows e.g. vector installed in schema 'extensions' (or 'public'), but cfg.ExtensionSchema() expects a different schema — typically because DATABASE_EXTENSIONS_SCHEMA is unset/defaulted while an admin pre-installed extensions elsewhere, or vice versa.","commonSituations":"Ops installed pgvector into a custom schema but .env omits DATABASE_EXTENSIONS_SCHEMA; migrating from single-tenant (extensions in public) to multi-tenant with a custom extension schema; DBA policy moving extensions out of public; mismatch between docker-compose env and docs config.","solutions":["Move the extension into the expected schema: ALTER EXTENSION vector SET SCHEMA <shared>; (repeat for pg_trgm).","Or set DATABASE_EXTENSIONS_SCHEMA=<actual-schema> in .env/docker-compose to match where the extension already lives.","Verify with: SELECT e.extname, n.nspname FROM pg_extension e JOIN pg_namespace n ON n.oid=e.extnamespace;","Keep DATABASE_EXTENSIONS_SCHEMA consistent across all instances sharing the database."],"exampleFix":"// before\n# .env\n# DATABASE_EXTENSIONS_SCHEMA unset; vector lives in 'extensions'\n// after\n# .env\nDATABASE_EXTENSIONS_SCHEMA=extensions  -- or run: ALTER EXTENSION vector SET SCHEMA public;","handlingStrategy":"validation","validationCode":"-- confirm where each extension actually lives before choosing DATABASE_EXTENSIONS_SCHEMA\nSELECT e.extname, n.nspname\n  FROM pg_extension e JOIN pg_namespace n ON n.oid = e.extnamespace\n WHERE e.extname IN ('vector','pg_trgm');","typeGuard":null,"tryCatchPattern":"if err := EnsureTenantSchema(ctx, cfg); err != nil {\n    var schema, expected string\n    if _, scanErr := fmt.Sscanf(err.Error(), \"extension %q is installed in schema %q\", new(interface{}), &schema); scanErr == nil {\n        log.Error().Msgf(\"set DATABASE_EXTENSIONS_SCHEMA=%s or ALTER EXTENSION SET SCHEMA\", schema)\n    }\n    return err\n}","preventionTips":["Set DATABASE_EXTENSIONS_SCHEMA explicitly in .env rather than relying on defaults","Keep it identical across every instance sharing the database","Include the pg_extension/pg_namespace query in deployment smoke tests","Document the chosen extension schema in runbooks next to DATABASE_URL"],"tags":["postgres","pgvector","extension","schema","configuration","multi-tenancy"],"backgroundTag":"extension-schema-mismatch","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}