Skip to content

driver-sql: richtext is emitted as varchar(255) while its markdown/html siblings get TEXT — a rich-text body is capped at 255 characters #11794

Description

@huangyiirene

Found while building the field-type agreement pin for #11565. Filed unassigned; deliberately not fixed there — that card is a MySQL diagnostic and this is an emission-rule defect on every dialect.

What

createColumn's text-family case in packages/drivers/driver-sql/src/sql-driver.ts lists text / textarea / html / markdown. richtext is not in it. It is also not in JSON_COLUMN_TYPES, so it falls through to the catch-all and is emitted as table.string(name) — knex's varchar(255).

The spec groups all three together as "Rich Content" (field.zod.ts: 'markdown', 'html', 'richtext') and puts all of them in STRING_VALUE_TYPES. Two of the three get an unbounded TEXT column. The third gets 255 characters.

The same fall-through catches three more STRING_VALUE_TYPES members whose values are routinely long: code (a code-editor field), signature and qrcode (both plausibly data URIs).

Evidence

Measured, not inferred — this is what the FieldType.options agreement pin added in #11565 compares against a really-created table, column by column:

richtext STRING_VALUE: true STRUCTURED_JSON: false -> varchar(255)
code STRING_VALUE: true STRUCTURED_JSON: false -> varchar(255)
signature STRING_VALUE: true STRUCTURED_JSON: false -> varchar(255)
qrcode STRING_VALUE: true STRUCTURED_JSON: false -> varchar(255)
markdown STRING_VALUE: true STRUCTURED_JSON: false -> text
html STRING_VALUE: true STRUCTURED_JSON: false -> text

Why it matters

varchar(255) is not a soft cap on either enforcing dialect. This is the exact write-side failure #11431 documents for the string family: a legal value is refused by MySQL with ER_DATA_TOO_LONG under STRICT_TRANS_TABLES, and by Postgres with 22001 value too long for type character varying(255). A rich-text body over 255 characters is an ordinary authored value, and nothing in the metadata declares that bound — the author declared richtext, not a length.

It is also a self-inflicted drift report: schema-drift.ts treats varchar(field.maxLength) as the expected physical shape of a bounded field, and these fields declare no bound.

Not prescribing a remedy

The obvious reading is that richtext belongs in the text-family case beside markdown and html (with the same #11374 keyed-and-bounded rule). Whether code / signature / qrcode belong there too, or whether the whole switch should be driven off the spec's STRING_VALUE_TYPES value class rather than a hand-maintained case list, is the design question — the hand-maintained list is what let one member of a three-member spec group diverge silently.

Scope note for whoever picks this up

Lands in the same createColumn switch as #11431 (string family / maxLength) and #11374 (keyed text). Same file, adjacent branches — worth serialising against those rather than running in parallel. Not blocked by either: this branch is independent of both.

The agreement pin from #11565 (sql-driver-11565-row-byte-budget.test.ts, "agrees with createColumn about every FieldType the spec declares") will need its expectation updated in the same PR — it currently pins the present behaviour, including this one.

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions