Found while implementing #11431 (the string family honouring its declared maxLength). Filed unassigned. Not fixed there: the remedy needs a seam createColumn does not have.
What
MySQL InnoDB caps the sum of a row's declared byte widths at 65535, independently of the per-column varchar ceiling. createColumn decides one column at a time and cannot see that budget, so an object whose string-family fields declare enough total width simply fails CREATE TABLE.
Evidence
Measured on live MySQL 8.0.46 (utf8mb4, InnoDB, DYNAMIC row format):
1 x varchar(16383) OK 4 x varchar(4096) ERROR 1118
2 x varchar(16383) ERROR 1118 32 x varchar(500) OK
15 x varchar(1024) OK 33 x varchar(500) ERROR 1118
16 x varchar(1024) ERROR 1118 64 x varchar(255) OK
65 x varchar(255) ERROR 1118
ERROR 1118 (42000): Row size too large. The maximum row size for the used table
type, not counting BLOBs, is 65535.
Postgres has no equivalent limit — it TOASTs; 40 x varchar(4096) creates cleanly. So this is MySQL-only.
Why it matters
The server's own error names no field and no declaration. It says "change some columns to TEXT or BLOBs" about a table the author described entirely in metadata, and nothing maps it back to the maxLength values that caused it. That is the same class of misleading diagnostic explainUnkeyableTextColumn was written for (#11374): a refusal an operator cannot act on without knowing the driver's internals.
It is reachable by ordinary authoring: sixteen fields declaring maxLength: 1024 is not an exotic object, and an AI-authoring a metadata app has no reason to suspect a cumulative limit exists.
Not currently triggered by this repo
Measured across every *.object.ts: the widest string-family bound declared anywhere is 2000, and no object carries more than six such fields. So no platform object is near the limit today — this is about authored apps.
Why it was not fixed in #11431
Two reasons, both structural rather than effort:
createColumn is per-column by signature. The budget is a per-TABLE fact, known only at the call site that iterates obj.fields.- Attaching a diagnostic means wrapping the shared
knex.schema.createTable call inside initObjects in a try/catch — a hot region that sibling cards are working in.
Direction (for triage — not prescribing)
Either a pre-flight check at the call site that sums the declared widths before issuing DDL and refuses with a message naming the widest offenders, or an ER_TOO_BIG_ROWSIZE translator alongside explainUnkeyableTextColumn. The pre-flight is the better shape — it can name every contributing field, where the post-hoc translator only knows the table failed.
Generated by Claude Code
Found while implementing #11431 (the string family honouring its declared
maxLength). Filed unassigned. Not fixed there: the remedy needs a seamcreateColumndoes not have.What
MySQL InnoDB caps the sum of a row's declared byte widths at 65535, independently of the per-column
varcharceiling.createColumndecides one column at a time and cannot see that budget, so an object whose string-family fields declare enough total width simply failsCREATE TABLE.Evidence
Measured on live MySQL 8.0.46 (utf8mb4, InnoDB, DYNAMIC row format):
Postgres has no equivalent limit — it TOASTs;
40 x varchar(4096)creates cleanly. So this is MySQL-only.Why it matters
The server's own error names no field and no declaration. It says "change some columns to TEXT or BLOBs" about a table the author described entirely in metadata, and nothing maps it back to the
maxLengthvalues that caused it. That is the same class of misleading diagnosticexplainUnkeyableTextColumnwas written for (#11374): a refusal an operator cannot act on without knowing the driver's internals.It is reachable by ordinary authoring: sixteen fields declaring
maxLength: 1024is not an exotic object, and an AI-authoring a metadata app has no reason to suspect a cumulative limit exists.Not currently triggered by this repo
Measured across every
*.object.ts: the widest string-family bound declared anywhere is 2000, and no object carries more than six such fields. So no platform object is near the limit today — this is about authored apps.Why it was not fixed in #11431
Two reasons, both structural rather than effort:
createColumnis per-column by signature. The budget is a per-TABLE fact, known only at the call site that iteratesobj.fields.knex.schema.createTablecall insideinitObjectsin a try/catch — a hot region that sibling cards are working in.Direction (for triage — not prescribing)
Either a pre-flight check at the call site that sums the declared widths before issuing DDL and refuses with a message naming the widest offenders, or an
ER_TOO_BIG_ROWSIZEtranslator alongsideexplainUnkeyableTextColumn. The pre-flight is the better shape — it can name every contributing field, where the post-hoc translator only knows the table failed.Generated by Claude Code