dotCMS / dotCMS/core

AI plugin: content delete/archive/unpublish unconditionally initializes pgvector extension even when dotAI is disabled

Open Beginner friendly
#36,895 0 comments 0 reactions 0 assignees View on GitHub

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 on AppConfig.isEnabled() via getAppConfig(hostId) (EmbeddingContentListener.java#L79-L93) — if no API key/URL is configured, it throws DotAIAppConfigDisabledException, 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 to onArchive, onDeleted, and the unpublish branches of onModified/onPublish, and unconditionally calls APILocator.getDotAIAPI().getEmbeddingsAPI().deleteEmbedding(dto).
  • EmbeddingsAPIImpl.deleteEmbedding (EmbeddingsAPIImpl.java#L140-L144) calls EmbeddingsFactory.impl.get(), and EmbeddingsFactory's constructor (EmbeddingsFactory.java#L44-L56) unconditionally runs initVector()initVectorExtension()CREATE EXTENSION vector if 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 / ERROR log 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 to CREATE 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 main HEAD 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.