AI plugin: content delete/archive/unpublish unconditionally initializes pgvector extension even when dotAI is disabled
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 970
- Forks
- 486
- Avg merge
- 3d 33m
- Merged PRs (30d)
- 170
Description
Summary
EmbeddingContentListener fires on every content archive, delete, and unpublish event, regardless of whether the dotAI App is configured/enabled for the host. The delete path calls EmbeddingsAPI.deleteEmbedding(...), which triggers first-touch construction of the EmbeddingsFactory singleton — and that constructor unconditionally attempts CREATE EXTENSION vector. On any environment where the DB role lacks rds_superuser (e.g. AWS RDS without the extension pre-provisioned), this throws on every single archive/unpublish/delete action, regardless of dotAI enablement:
ERROR: permission denied to create extension "vector"
Hint: Must be rds_superuser to create this extension.
com.dotmarketing.exception.DotRuntimeException: ERROR: permission denied to create extension "vector"
at com.dotcms.ai.db.EmbeddingsFactory.runSQL(EmbeddingsFactory.java:99)
at com.dotcms.ai.db.EmbeddingsFactory.initVectorExtension(EmbeddingsFactory.java:119)
at com.dotcms.ai.db.EmbeddingsFactory.initVector(EmbeddingsFactory.java:54)
at com.dotcms.ai.db.EmbeddingsFactory.<init>(EmbeddingsFactory.java:47)
at com.dotcms.ai.listener.EmbeddingContentListener.deleteFromIndexes(EmbeddingContentListener.java:164)
at com.dotcms.ai.listener.EmbeddingContentListener.onPublish(EmbeddingContentListener.java:62)
Root cause — asymmetric enablement check
- Add/publish path (
EmbeddingContentListener.addToIndexesIfNeeded, EmbeddingContentListener.java#L114-L135) correctly gates onAppConfig.isEnabled()viagetAppConfig(hostId)(EmbeddingContentListener.java#L79-L93) — if no API key/URL is configured, it throwsDotAIAppConfigDisabledException, which is caught and results in a safe no-op. - Delete path (
EmbeddingContentListener.deleteFromIndexes, EmbeddingContentListener.java#L141-L150) has no equivalent check. It's subscribed toonArchive,onDeleted, and the unpublish branches ofonModified/onPublish, and unconditionally callsAPILocator.getDotAIAPI().getEmbeddingsAPI().deleteEmbedding(dto). EmbeddingsAPIImpl.deleteEmbedding(EmbeddingsAPIImpl.java#L140-L144) callsEmbeddingsFactory.impl.get(), andEmbeddingsFactory's constructor (EmbeddingsFactory.java#L44-L56) unconditionally runsinitVector()→initVectorExtension()→CREATE EXTENSION vectorif not already present, with no enablement check of any kind.
So: any host with dotAI disabled will still attempt to provision the pgvector extension on every content archive/unpublish/delete.
Impact
- Continuous
DotRuntimeException/ERRORlog spam on every archive/unpublish/delete action for customers who have never enabled dotAI, on any Postgres setup where the app's DB role isn't privileged enough toCREATE EXTENSION(common on shared/communal RDS clusters where extension installation is a manual, privileged, per-database step). - Wasted DB round-trip per content lifecycle event.
- Currently non-fatal (exception appears to be caught above the listener), but worth confirming it can't regress into blocking the actual archive/unpublish/delete under load or on other PG configurations.
Suggested fix
Gate EmbeddingContentListener.deleteFromIndexes behind the same AppConfig.isEnabled() check already used in addToIndexesIfNeeded, so the delete path no-ops when dotAI isn't configured for the host — matching the existing behavior of the add/publish path.
Environment
- dotCMS version: 26.07.17-01 (evergreen)
- Confirmed present at
mainHEAD in this checkout as of investigation date. - Postgres: AWS RDS, communal/shared cluster, pgvector extension available on the instance but not installed per-database; app DB role not granted
rds_superuser.
Found while investigating a support case (dotAI disabled, customer seeing permission denied to create extension "vector" errors in application logs on every content publish/archive/delete).
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with EmbeddingContentListener.java, comparing addToIndexesIfNeeded at lines 114-135 with deleteFromIndexes at lines 141-150 and the getAppConfig path at lines 79-93. Trace the delete call through EmbeddingsAPIImpl.deleteEmbedding and EmbeddingsFactory to understand the extension initialization. Done means archive, delete, and unpublish events no-op when dotAI is disabled without attempting CREATE EXTENSION vector, while enabled behavior remains unchanged.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, postgresql
- Domain
- backend, databases
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100