hibernate/hibernate-orm · error · MappingException

write expression must contain exactly one value placeholder

Error message

write expression must contain exactly one value placeholder ('?') character near <column name="%s" ... write="%s" /> for <%s name="%s" />

What it means

A custom write fragment (write='...' on a <column>) is a SQL template used when Hibernate writes the column; exactly one '?' marks where the bound parameter is substituted. The binder validates the fragment with the pattern 'exactly one question mark' and rejects fragments containing zero or multiple placeholders, echoing the column name, the fragment, and the owning element.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/RelationalValueSourceHelper.java:453

				errorMessage = String.format(
						Locale.ENGLISH,
						"write expression must contain exactly one value placeholder ('?') character near <column name=\"%s\" ... write=\"%s\" /> for <%s name=\"%s\" />",
						columnMapping.getName(),
						customWrite,
						columnsAndFormulasSource.getSourceType().getElementName(),
						columnsAndFormulasSource.getSourceName()
				);
			}
			else {
				errorMessage = String.format(
						Locale.ENGLISH,
						"write expression must contain exactly one value placeholder ('?') character near <column name=\"%s\" ... write=\"%s\" /> for <%s />",
						columnMapping.getName(),
						customWrite,
						columnsAndFormulasSource.getSourceType().getElementName()
				);
			}
			throw new MappingException( errorMessage, sourceDocument.getOrigin() );
		}
	}

}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Rewrite the fragment so it contains exactly one '?' where the value must be bound, e.g. write='upper(?)'
  2. For zero-parameter expressions (constants, function results), prefer a database default or a generated column instead of a write fragment
  3. If the expression genuinely needs two parameters, it cannot be a column write fragment - move the logic into a trigger or custom INSERT/UPDATE SQL

Example fix

// before
<column name='code' write="concat('P-', ?, '-S')" read="substr(code, 3)"/>

// after - exactly one placeholder
<column name='code' write="concat('P-', upper(?))" read="substr(code, 3)"/>
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight: custom write fragments must contain exactly one '?' placeholder
String write = columnElement.getAttribute("write");
int placeholders = write.length() - write.replace("?", "").length();
if (placeholders != 1)
    throw new IllegalArgumentException("write must contain exactly one '?', found " + placeholders + " in: " + write);

Try / catch

catch (org.hibernate.boot.MappingException e) at Metadata build: the message prints the column, fragment and owning element - rewrite the fragment so exactly one '?' marks the bound parameter

Prevention

When it happens

Trigger: A <column> with write='now()' (zero placeholders), write='coalesce(?, ?)' or write="concat('P-', ?, '-', ?)" (two or more placeholders). Zero-parameter and multi-parameter expressions both fail.

Common situations: Copy-pasting from read fragments (read= needs no placeholder); writing expressions that take several bound values; trying to escape a literal question mark by doubling it.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/1100b014c2962c4b. Report an issue: GitHub.