Found while stating what the #16091 probe set cannot reach (PR #16298). Every probe on that card is a real FieldType member; these two shapes are not, so no sweep there could have found them.
The two defaults
SqlDriver.createColumn const type = field.type || 'string';
generate.ts String(fieldDef.type || 'text') (both formats)
'string' heads createColumn's STRING-family arm, which sizes the column from declaredVarcharLength(field) — the declared maxLength verbatim, knex's 255 without one. 'text' heads the generators' TEXT arm, which is unbounded unless the column is keyed. Two different families, from the same declaration.
An unknown type string splits the same way for a different reason: the driver falls to its catch-all (table.string(name), varchar(255)), the generators to their own default: arm (TEXT).
The measurement
Live PostgreSQL 16.13, all three producers driven from one object, columns read back out of information_schema.columns:
driver sql gen ts gen
{ maxLength: 100 } (no `type`) character varying(100) text text
{ type: 'this_is_not_a_field_type',
maxLength: 100 } character varying(255) text text
Both directions of harm are present in the first row: the platform REFUSES a 101-character value that both generated tables accept.
Reachability, honestly
Neither shape parses. FieldSchema requires type and rejects a non-member at [type] (#12593 measured the same for 'string' itself). So this is the UNVALIDATED authoring door only — a config loaded without os validate, a hand-built object, a metadata row written by something other than the authoring path. fieldTypeToSql's own docblock already says that door exists and can deliver a type string.
That is exactly why it is filed rather than repaired inside #16298: the fix is one character of default text on each side, but WHICH side moves is a decision about what an unvalidated field means, and #16091's ruling ("the generator follows the driver", #15521) was given for declarations that parse.
The narrower half
FieldType.options omits 'string' and there is no Field.string builder (#12593), so createColumn's case 'string': is reachable only through this same door — the driver's default and its own arm are consistent with each other, and it is the generators' || 'text' that disagrees.
Found while stating what the #16091 probe set cannot reach (PR #16298). Every probe on that card is a real
FieldTypemember; these two shapes are not, so no sweep there could have found them.The two defaults
'string'headscreateColumn's STRING-family arm, which sizes the column fromdeclaredVarcharLength(field)— the declaredmaxLengthverbatim, knex's 255 without one.'text'heads the generators' TEXT arm, which is unbounded unless the column is keyed. Two different families, from the same declaration.An unknown
typestring splits the same way for a different reason: the driver falls to its catch-all (table.string(name),varchar(255)), the generators to their owndefault:arm (TEXT).The measurement
Live PostgreSQL 16.13, all three producers driven from one object, columns read back out of
information_schema.columns:Both directions of harm are present in the first row: the platform REFUSES a 101-character value that both generated tables accept.
Reachability, honestly
Neither shape parses.
FieldSchemarequirestypeand rejects a non-member at[type](#12593 measured the same for'string'itself). So this is the UNVALIDATED authoring door only — a config loaded withoutos validate, a hand-built object, a metadata row written by something other than the authoring path.fieldTypeToSql's own docblock already says that door exists and can deliver atypestring.That is exactly why it is filed rather than repaired inside #16298: the fix is one character of default text on each side, but WHICH side moves is a decision about what an unvalidated field means, and #16091's ruling ("the generator follows the driver", #15521) was given for declarations that parse.
The narrower half
FieldType.optionsomits'string'and there is noField.stringbuilder (#12593), socreateColumn'scase 'string':is reachable only through this same door — the driver's default and its own arm are consistent with each other, and it is the generators'|| 'text'that disagrees.