Skip to content

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.