Schema definition errors
Thrown as SchemaDefinitionError (code: "schemaDefinition"). Each entry is an identifier (error.id), then the message as the error states it, where {expression} stands for the value of that expression in the source ({…} for one too long to show), then what to do about it: the text useFullErrorMessages(messages) and explain(error) add, where {name} stands for the error's parameter of that name. See Errors.
schema.arrayElement
t.array() takes a field type with no modifiers, such as t.array(t.string()).
Put the modifiers on the array: t.array(t.string()).nullable().
schema.assocFieldClash
{ownerMeta.name} has a field and an association that are both named "{name}".
A preloaded association is a property of the row, so rename one of them (the foreign-key field is usually "{name}Id").
schema.assocFieldVirtual
the {role} field "{name}" of {meta.name} is virtual, so it is not stored and cannot be part of an association.
Point the association at a stored field: remove .virtual() from it, or use another field.
schema.assocKeyCount
the foreign key has {foreignKey.length} field(s) ({quoted(foreignKey)}) but it points at {references.length} ({quoted(references)} on {referencedMeta.name}).
Give one foreign-key field per referenced field, in the same order.
schema.assocKeyOption
{option} must be a field name, or an array of field names for a composite key.
Pass a field name, as in { foreignKey: "authorId" }, or an array of them for a composite key.
schema.assocKeyType
the foreign key {holderMeta.name}.{key.name} is of type {key.type.name}, but {referencedMeta.name}.{referenced.name}, which it points at, is of type {referenced.type.name}.
Declare both with the same type.
schema.assocNoPrimaryKey
{meta.name} has no primary key, so the field the key points at cannot be guessed.
Pass { {option} }.
schema.assocOnEmbedded
{ownerMeta.name} is an embedded schema: it is stored inside its parent's row and has no table to associate.
Move the association to the parent schema.
schema.assocOnReplace
onReplace must be one of {quoted(allowed)} for {context.kind}.
Pick one of the listed modes; "error" (the default) refuses to replace existing associated rows.
schema.assocOptionsNotObject
the options of {context.kind} must be an object, but got {describe(raw)}.
Pass the options as an object, as in hasMany(() => Post, { foreignKey: "authorId" }).
schema.assocOrderBy
{problem}
Pass field names, as in ["createdAt"], or objects of a field and a direction, as in [{ createdAt: "desc" }].
schema.assocOrderByFieldMissing
An order is written with the target's field names.
schema.assocReservedName
"{name}" cannot be the name of an association: "constructor", "__proto__", "toJSON", "fields" and names that start with "$" are reserved.
Rename the static member.
schema.assocShadowedByMember
{ownerMeta.name} defines "{name}" as a getter, method or property of the class, and "{name}" is also an association.
A preloaded association is a property of the row, so the class member would hide it or make it impossible to set. Rename one of them.
schema.assocTargetEmbedded
{targetMeta.name} is an embedded schema and has no table, so it cannot be the {role} of an association.
Declare it as a field: t.embedOne(() => {name}).
schema.assocTargetNotSchema
the function for the {role} returned {describe(target)}, not a schema class.
The function must return a class declared with Schema(...), such as () => Post.
schema.assocTargetThrew
the function for the {role} threw ({…}).
It is called when associations are first used, by which time every schema module must have been loaded.
schema.assocTargetThunk
the {role} must be given as a function that returns the class.
Pass a function that returns the class, so that classes can refer to each other: {example}.
schema.assocUnknownOption
{context.kind} has no option "{key}". It takes {allowed.join(", ")}.
Remove the option, or check its spelling against the ones listed.
schema.assocWhereFieldMissing
A where condition is written with the target's field names.
schema.assocWhereOption
{option} must be an object from name to value.
Pass an object from field name to value, such as { published: true }.
schema.assocWhereUndefined
{option}.{key} is undefined.
Use null to match NULL, or leave the key out.
schema.autogenerateFunction
autogenerate() takes a function that returns the value.
Pass a function that makes the value, such as autogenerate(() => crypto.randomUUID()).
schema.autogenerateType
autogenerate() without a function has no value to make for the type {type.name}.
autogenerate() without a function works for t.uuid() (a UUID v7) and for timestamps (the current time). For other types, pass the function: autogenerate(() => value).
schema.belongsToKeyMissing
Declare the field (as in authorId: t.integer()), or pass { foreignKey } with the field that holds the key.
schema.bigintMode
t.bigint: mode must be "bigint" or "number", but got {JSON.stringify(mode)}.
Pass { mode: "bigint" } (the default) or { mode: "number" }.
schema.columnName
column() needs the column name as a non-empty string.
Pass the column name, as in column("pw_hash").
schema.columnTaken
{label}: the fields "{other}" and "{name}" are both stored in the column "{field.column}".
Give one of them another column with .column("…").
schema.createWithTwice
{name}: the association "{assoc}" is listed twice in createWith().
List each association once.
schema.createWithUnknown
{name} has no association "{assoc}". It has: {…}.
Preload only associations the schema declares.
schema.dateAsOption
t.date: as must be "string" or "date", but got {JSON.stringify(as)}.
Pass { as: "string" } (the default) or { as: "date" }.
schema.decimalPrecision
t.decimal: precision must be a whole number from 1 to 1000, but got {String(precision)}.
Pass a precision from 1 to 1000, as in t.decimal({ precision: 10, scale: 2 }).
schema.decimalScale
t.decimal: scale must be a whole number from 0 to the precision ({precision}), but got {String(scale)}.
Pass a scale from 0 to the precision, as in t.decimal({ precision: 10, scale: 2 }).
schema.defaultValue
default() needs a value, or a function that returns one.
To allow a missing value, use nullable().
schema.embedModifier
{at} is an embed, which cannot be a primary key or virtual.
Remove .primaryKey() or .virtual() from the embed field. An embed is stored in its parent's JSON column; give the embedded schema its own key field if its items need one.
schema.embedSchemaThunk
t.{factory}() takes a function that returns the embedded schema class.
Pass a function that returns the class, as in t.embedOne(() => Address) or t.embedMany(() => Address), so that the class may be declared after the field.
schema.enumDuplicate
t.enum values must be distinct, but got {JSON.stringify(keys)}.
List each member once.
schema.enumEmpty
t.enum needs at least one value.
Give t.enum at least one member, as in t.enum(["admin", "member"]).
schema.enumMappingAmbiguous
t.enum mapping is ambiguous: {JSON.stringify(key)} is a key and also the stored value of {JSON.stringify(other)}, so input {JSON.stringify(key)} could mean either.
Choose stored values that are not also member names.
schema.enumMappingDuplicate
t.enum mapping values must be distinct, but got {stored.map(describeMember).join(", ")}.
Give every member its own stored value.
schema.enumMappingValues
t.enum mapping values must be all strings or all whole numbers, but got {stored.map(describeMember).join(", ")}.
Map every member to a string, or every member to a whole number, as in t.enum({ low: 1, high: 2 }).
schema.enumMemberType
t.enum values must be strings, but got {describeMember(key)}.
For other stored values use a mapping: t.enum({ low: 1, high: 2 }).
schema.enumMembers
t.enum takes a list of strings or a mapping, but got {…}.
Pass a list of strings, t.enum(["admin", "member"]), or a mapping, t.enum({ low: 1, high: 2 }).
schema.fieldsNotObject
{label}: the fields must be an object from field name to type, such as { id: t.integer().primaryKey() }, but got {describe(declared)}.
Pass the fields as the second argument of Schema() (or the first of EmbeddedSchema()), an object whose values are field types made with t.
schema.foreignKeyRequired
{kind} needs { foreignKey }: the field on {targetMeta.name} that points at {ownerMeta.name}.
Pass the field, as in {kind}(() => {target}, { foreignKey: "authorId" }).
schema.generatedTwice
{at} is both database-generated and autogenerated.
Only one side can produce the value: remove .dbGenerated() or .autogenerate().
schema.hasKeyMissing
Declare the field on {target} (as in authorId: t.integer()), or correct { foreignKey }.
schema.joinKeyFieldMissing
Pass { joinKeys } with fields of {join}.
schema.joinKeyType
the join key {joinMeta.name}.{joinField.name} is of type {joinField.type.name}, but {side.name}.{key.name}, which it points at, is of type {key.type.name}.
Declare both with the same type.
schema.joinKeysAmbiguous
the join keys cannot be worked out: {joinMeta.name} declares {found.length} belongsTo association(s) to {sideMeta.name} and exactly one, with a single foreign key, is needed.
Pass { joinKeys: { owner, target } } with the fields of {name}.
schema.joinKeysOption
joinKeys must be { owner, target }, each the name of a {unit} of the join table.
Pass joinKeys: { owner: "...", target: "..." }, each naming a {unit} of the join table.
schema.joinKeysRequired
manyToMany through the table "{through}" needs joinKeys with that table's column names.
Pass joinKeys, as in { joinThrough: "{through}", joinKeys: { owner: "post_id", target: "tag_id" } }: owner is the column that points at {owner}, target the one that points at {target}.
schema.joinKeysSame
joinKeys.owner and joinKeys.target are both "{owner}".
They are two different {unit}s.
schema.joinKeysSelf
{ownerMeta.name} is on both sides of this manyToMany, so the join keys cannot be told apart.
Pass { joinKeys: { owner, target } } with the fields of {name}.
schema.joinThroughEmpty
joinThrough is an empty string.
Give the join table's name.
schema.joinThroughRequired
manyToMany needs { joinThrough }: the name of the join table (with joinKeys), or a function returning its schema class.
Pass { joinThrough: "posts_tags", joinKeys: { owner, target } } with the join table's name, or { joinThrough: () => PostTag } with its schema class.
schema.joinWhereFieldMissing
A joinWhere condition is written with the field names of {join}.
schema.keylessRow
{className(row)} has no primary key, so its rows have no key value.
The schema is declared with { primaryKey: false }, or is an embedded schema without a key field.
schema.keylessWithKey
{label}: { primaryKey: false } says the table has no key, but the field "{primaryKey[0]?.name}" is declared with .primaryKey().
Remove one of the two.
schema.manyToManyCompositeKey
manyToMany needs {meta.name} to have a primary key of exactly one field, because a join table holds one column for each side. {meta.name} has {meta.primaryKey.length}.
Give the schema a single-field key, or declare the join as a schema class with belongsTo associations and use hasMany with through.
schema.memberShadowsField
{name} defines "{field}" as a getter, method or property of the class, and "{field}" is also a field.
A row holds each field as its own property, so the class member would hide it or make it impossible to set. Rename the member.
schema.namingOption
{label}: naming must be "snake_case", "camelCase" or a function from field name to column name.
Pass naming: "snake_case" (the default for tables), naming: "camelCase", or a function such as (field) => field.toLowerCase().
schema.namingResult
{label}: the naming function returned {describe(column)} for the field "{field}".
It must return the column name.
schema.noConstructor
{name} has no public constructor: a row comes only from the database.
Describe a new record with a changeset instead: cast({name}, params, [...]) or change({name}, values).
schema.noPrimaryKey
{label}: no field is the primary key.
Add .primaryKey() to the key field, as in id: t.integer().primaryKey(), or pass { primaryKey: false } as the third argument for a table without one.
schema.notFieldType
{label}: field "{name}" is not a field type.
Declare it with t, as in {name}: t.string(). Associations are static members of the class, not fields.
schema.notFieldTypeValue
Expected a field type such as t.integer() or t.string().
Use a field type from t, such as t.integer() or t.string(), or a type made with defineType() and wrapped as t.type(MyType).
schema.notRow
primaryKeyOf() expects a row: an object returned by a query or a write.
Pass a row returned by a query or a write, not a plain object or a changeset.
schema.notSchemaClass
Expected a schema class (a class that extends Schema(...) or EmbeddedSchema(...)), but got {describe(schema)}.
Pass the class you declared with class User extends Schema("users", { ... }) {}, not an instance, a row or a plain object.
schema.nullDefault
{at} has the default null but is not nullable.
Add .nullable().
schema.nullableKey
{at} is a primary key and nullable.
A key always has a value: remove .nullable().
schema.onReplaceOption
t.{factory}(): onReplace must be one of {…}.
Pick one of the listed modes; "error" (the default) refuses to replace an existing embed.
schema.optionsNotObject
{label}: the options must be an object, but got {describe(options)}.
Pass the options as an object, such as { schema: "tenant_1" }, or leave them out.
schema.precisionOption
{builder}: precision must be "s", "ms" or "us", but got {JSON.stringify(precision)}.
Pass precision "s", "ms" or "us", or leave it out for the type's default.
schema.primaryKeyOption
{label}: primaryKey can only be false, for a table without a key.
A key is declared on its field: id: t.integer().primaryKey().
schema.referencedFieldMissing
Pass { references } with the field the key points at.
schema.reservedName
{at} has a reserved name.
A field cannot be named "constructor", "__proto__" or "toJSON", or start with "$". Rename it, and keep the column with .column("{name}").
schema.schemaOption
{label}: schema must be the name of the database schema, as a non-empty string.
Pass the database schema's name, as in { schema: "tenant_1" }, or leave the option out for the connection's default.
schema.stateNotRow
stateOf() expects a row: an object returned by a query or a write.
Pass a row returned by a query or a write: a plain object or a changeset has no state.
schema.tableName
Schema() was given {describe(source)} as the table name.
Pass the table name as a non-empty string: Schema("users", { ... }).
schema.throughCombined
through cannot be combined with {others.join(", ")}.
Remove the other options: the associations through follows already say how the rows are found.
schema.throughPath
through must be an array of at least two association names to follow.
Pass the names of the associations to follow, as in {kind}(() => Comment, { through: ["posts", "comments"] }).
schema.throughUnknownStep
through follows "{step}" on {currentMeta.name}, but {currentMeta.name} has no such association. It has: {…}.
Follow associations the schema declares, in the order the path takes them.
schema.throughWrongTarget
through [{quoted(path)}] ends at {currentMeta.name}, but the association is declared with {context.metaOf(target).name} as its target.
Make the last association of the path point at the declared target, or change the target to the class the path ends at.
schema.timestampsField
timestamps(): {option} must be a field name, or false to leave the field out.
Pass the field name as a string, as in timestamps({ createdAt: "insertedAt" }), or false to leave that field out.
schema.timestampsSameName
timestamps(): createdAt and updatedAt are both named "{String(createdAt)}".
Give them different names, or pass false for one.
schema.timestampsType
timestamps(): type must be a timestamp type with no modifiers, such as t.timestamp() or t.localTimestamp().
Pass a timestamp type such as t.timestamp() or t.localTimestamp(), without modifiers: timestamps() adds its own.
schema.typeCast
Type "{name}": cast must be a function that returns { success: true, data } or { success: false }, but it is {describe(cast)}.
Pass cast: (value) => ({ success: true, data: value }), returning { success: false } for a value it rejects.
schema.typeCustomSql
Type "{typeName}": {path}.sql must be a plain SQL type name such as "citext", "numeric(10, 2)" or "public.mood[]".
It is written into the SQL text, so it must be a constant and can never come from user data.
schema.typeDbKind
Type "{typeName}": {path} must be a column type such as { kind: "text" }, but it is {describe(db)}.
Give db a column type, such as { kind: "text" }, { kind: "array", of: { kind: "integer" } } or { kind: "custom", sql: "citext" }.
schema.typeMember
Type "{name}": {member} must be a function or be left out, but it is {describe(fn)}.
Pass a function, or leave the member out to use the identity.
schema.typeName
defineType needs a non-empty name (it appears in error messages), but got {describe(name)}.
Pass a name, as in defineType({ name: "money", ... }); it appears in error messages.
schema.typeNotDefined
t.type() takes a type made with defineType(): t.type(MoneyType).
For a built-in type use its own function, such as t.string().
schema.typeOptionsDepth
The options of a parameterized type are nested more than {MAX_OPTIONS_DEPTH} levels deep.
They probably contain themselves; options must be plain data.
schema.typeUnknownKind
Type "{typeName}": {path}.kind is {JSON.stringify(kind)}, which is not a column kind. The kinds are {[...SIMPLE_KINDS].join(", ")}, "array" and "custom".
Use one of the listed kinds; { kind: "array", of } for an array, or { kind: "custom", sql } for any other SQL type.
schema.uniqueOption
unique must be true or false.
Pass unique: true or unique: false, or leave it out.
schema.virtualJsonOption
virtual(): json must be true or false.
Pass { json: true } to keep the field in the row's JSON, or leave the options out: a virtual field is left out by default.
schema.virtualOptions
virtual() takes no options, or { json: true }.
Pass { json: true } to keep the field in the row's JSON, or leave the options out.
schema.virtualStored
{at} is virtual, so it is never stored: it cannot also be a primary key, database-generated or autogenerated.
Remove .virtual() or the other modifier.
schema.virtualUnknownOption
virtual() has no option "{unknownKey}". It takes json.
Remove the option, or check its spelling: the one option is json.
schema.writableOption
writable() takes "always", "insert" or "never".
Pass "always" (the default), "insert" for a field set only when the row is inserted, or "never" for a field only the database writes.

