dotCMS / dotCMS/core

Field variables added in-session are silently deleted when the field's properties are saved

Open
#37,301 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

OKR : Customer Support Team : Maintenance
Dominant language
Java
Stars
970
Forks
486
Avg merge
3d 33m
Merged PRs (30d)
170

Description

Problem Statement

Field variables added to a content type field during a browser session are silently deleted as soon as that field's properties are saved. There is no warning, no error toast, and no console error — the variable simply disappears.

This is data loss in a normal, expected editing flow: an editor adds a field variable, then tweaks something on the same field's Overview tab (Hint, Name, Default Value, a checkbox), clicks Save, and the field variable they just created is gone.

Found while QA'ing #35512 (verifying PR #36341). This defect is not caused by that PR — see "Regression status" below.

Root cause (identified): the field-edit dialog holds a field object snapshotted at page load. The Field Variables tab writes through its own endpoint (POST /api/v1/contenttype/{ctId}/fields/id/{fieldId}/variables) and never refreshes that snapshot. When the field's properties are then saved, the client issues:

PUT /api/v3/contenttype/{ctId}/fields/{fieldId}
{"field": { ... , "fieldVariables": [], ... }}

The backend treats that stale fieldVariables array as authoritative and replaces the field's variables with it, deleting anything added since page load.

Captured request body from a real reproduction:

{"field":{"clazz":"com.dotcms.contenttype.model.field.ImmutableTextField","contentTypeId":"bb975b4dbd1e79168c130dd3b3fcbf69","dataType":"TEXT","fieldType":"Text","fieldVariables":[],"id":"66f7c1cc436224db0e865ab94579d85b","name":"Field One EDITED","variable":"fieldOne","hint":"a hint added after the variable", ...}}

Browser & OS: Chrome 152 / macOS. Not browser-specific — the defect is in the request payload.

Steps to Reproduce

100% reproducible. Verified twice, on two different fields, on two different field types (Text, Checkbox).

  1. Edit any content type, then click any field to open the field-edit dialog.
  2. Go to the Field Variables tab, add a variable — key newVar, value newValue — and save it.
    • Confirm it saved: GET /api/v1/contenttype/{ctId}/fields/id/{fieldId}/variables returns newVar. ✅
  3. Switch to the Overview tab, change any property (e.g. type something into Hint), and click Save.
  4. Re-check the variables: GET /api/v1/contenttype/{ctId}/fields/id/{fieldId}/variables

Expected: newVar is still there. The property save should not touch field variables.
Actual: newVar is gone. Count is 0. The property change itself saved correctly.

Reopening the Field Variables tab confirms the variable is missing from the UI as well.

Precise boundary of the bug (isolated during QA — useful for the fix):

Scenario Result
Variable existed at page load, then field properties saved SurvivesGET /api/v1/contenttype/id/{ctId} echoes fieldVariables populated, so the snapshot round-trips it correctly
Variable added in-session via the Field Variables tab, then field properties saved Silently deleted

So the trigger is specifically the staleness of the dialog's field snapshot, not the field save itself.

Acceptance Criteria
  • A field variable added during a session survives a subsequent save of that field's properties.
  • Saving a field's properties never deletes field variables that the user did not explicitly delete.
  • Decide and implement the correct contract for PUT /api/v3/contenttype/{ctId}/fields/{fieldId}: either the client must send a current fieldVariables array, or the endpoint should ignore fieldVariables on a field update so a field PUT is not implicitly a variable-replacement operation. (The latter is more robust — a property update arguably should never be able to destroy variables.)
  • Regression coverage: add a variable, save field properties, assert the variable still exists.
dotCMS Version

Reproduced on dotcms/dotcms:trunk, build 1.0.0-SNAPSHOT — August 31, 2026 (latest main).

Believed to affect all recent versions — see Regression status.

Severity

High - Major functionality broken

(Silent, unwarned data loss. The user has no indication anything was destroyed, and no way to know to re-add it.)

Links

NA


Regression status — not introduced by #36341

Verified by code inspection rather than by booting a pre-fix build:

  • The deleted FieldService.updateField and the new DotFieldService.updateField issue the identical PUT /api/v3/contenttype/{ctId}/fields/{fieldId} with { field }.
  • The pre-refactor saveFieldsHandler did Object.assign(this.currentField, fieldToSave) where currentField came from this.fieldRows — also a page-load snapshot, with the same staleness.

Neither the old nor the new code path refreshes the field object after a variable write, so this behavior almost certainly predates the refactor. Not confirmed against a pre-fix build.

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 by tracing PUT /api/v3/contenttype/{ctId}/fields/{fieldId} alongside POST /api/v1/contenttype/{ctId}/fields/id/{fieldId}/variables, using the supplied reproduction to confirm the stale fieldVariables payload. Add regression coverage that creates a variable, saves a field property, and verifies the variable remains present. Done means property saves no longer delete variables the user did not explicitly remove.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
api, backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.