Reference
Error codes
Every diagnostic Undra raises, from a macro at compile time, from schema validation, from the runtime or from the undra command, has a stable code, a fixed shape and a fix. The link at the end of each message lands on its code below.
How to read one
A diagnostic says what is wrong, why the rule exists and how to fix it. This one is verbatim from the macro test suite:
error[undra::E0004]: callback `Arc<dyn Listener>` cannot be a field of a record or enum (`Listener` is a callback interface)
= note: a callback is an instance with a lifetime, not a value: it cannot be copied, compared, stored in a record or mirrored from a signal
= help: keep an id or a record here, and take the callback as a parameter of the method that needs it
= docs: https://shreypdev.github.io/undra/docs/errors.html#E0004All codes
| Code | Meaning |
|---|---|
C0001 | no undra.toml from start up to the filesystem root |
C0002 | a configuration or schema file is unusable |
C0003 | a tool is not installed |
C0004 | a build tool exited with a failure |
C0005 | the core crate is missing, or is not an Undra core |
C0006 | the schema could not be extracted from the built core |
C0007 | the schema cannot be turned into bindings (bindgen diagnostics) |
C0008 | the command would overwrite something it must not |
C0009 | an argument is unusable |
C0010 | an I/O operation failed |
C0011 | the Rust toolchain lacks a compilation target |
C0012 | the platform is not available on this machine |
C0013 | the dev server failed to start or crashed |
C0014 | the project's Undra does not match: the core's comes from elsewhere, or it is newer |
E0001 | unsupported type in a public position |
E0002 | generic parameter, or a generic type spelled with its arguments |
E0003 | lifetime in a public signature |
E0004 | a trait object, dyn or impl Trait that is not a callback parameter, or a callback where one may not stand (ADR-041) |
E0005 | Result / Stream outside return position |
E0006 | map key type not allowed |
E0007 | unsupported item shape or placement of an Undra attribute |
E0008 | unknown or misplaced #[undra(..)] attribute or macro argument |
E0010 | invalid #[undra::error] variant |
E0011 | store and #[undra::api(store)] impl block disagree |
E0012 | trait object in a record field |
E0013 | store cannot be restored automatically |
E0020 | &mut self receiver |
E0021 | self by value |
E0022 | non-Send future in an async method: rustc's own error, pointed at the method by an assertion named after this code |
E0030 | port method with a non-wire parameter |
E0031 | event port method that is not a plain fn(..) returning () |
E0032 | invalid port trait shape |
E0033 | the error type of a port method has no From<PortError> |
E0040 | query without key, mutation with stale, or another invalid query argument |
E0041 | query or mutation function with an invalid signature |
E0042 | query whose success value is () or an Option |
E0050 | duplicate type name, id or variant index |
E0051 | a name that collides after case conversion or is not an identifier |
E0052 | an item named like a standard library item, with another id |
E0060 | a spelling that looks like a built-in Undra type is another type |
E0061 | the name written is not the declared name of the type, or the type is not declared with #[undra::api] |
E0062 | a port call could not be answered and its method has no error channel: a runtime message |
E0063 | nested Option<Option<T>> |
E0064 | an object (#[undra::api] impl) used where a value is expected, or a value used as an object, or an object where objects may not stand (ADR-040) |
E0065 | a signal of a store written off its owning runtime's core (ADR-035): a runtime message |
E0066 | a #[undra::migrate] hook with a wrong target or shape (ADR-037; addition) |
E0070 | a named instantiation of a generic data type that is declared twice or outside the crate of its template |
E0071 | a method of a #[undra::callback] trait that is neither fire-and-forget nor async with a Result, or whose name starts with __ (ADR-041) |
E0072 | the instantiation list of a generic function or method (generic(T = [Todo, Note])) is empty, repeats a type, lists something that is not a named value type, names a type parameter the function does not have, or the function has several type parameters; a schema whose generic labels do not describe their definitions (ADR-058; addition) |
E0073 | an infinite query that does not meet ADR-043's shape: no item_key or one that names no field of the rows, no or more than one #[undra(cursor)] parameter, a cursor that is not Option<C> or is in the key, a success type that is not Page<T, C>, rows that are not a record |
E0074 | the impl block of a generic object that is not for the type with its own type parameters, each exactly once, or a method of a generic object with type parameters of its own (ADR-058; addition) |
Types and shapes#
E0001 unsupported type in a public position#
Raised by macros, schema validation, the Encode/Decode bounds.
unsupported type in a public position (lists the type and the allowed set); includes i128/u128 (the help points at Decimal, Uuid or a String newtype), DateTime<Local> and DateTime<FixedOffset> ("convert to Utc; offsets do not cross"), a type of the uuid, chrono, time, rust_decimal or bytes crate that only that crate has (DateTime<Utc>, OffsetDateTime, TimeDelta, ..) spelled without the matching feature of undra (one error naming the feature), a Lazy<T> that is not a store field, or is inside a Signal, Computed or DerivedList (ADR-043), a DerivedList field without its row type (ADR-039), Handle (no schema type; an object crosses as Arc<T> or &T, ADR-040), Arc<T> of a built-in or an Rc, a Result whose error type is not a #[undra::error] enum, a Ctx parameter that is misplaced (on a method, not first, or &mut), and a type used as a value that cannot cross (an Encode/Decode bound that is not met: a struct without #[undra::api])
| What you see | Why | Fix |
|---|---|---|
Plain cannot cross the boundary by value | a value crosses as a scalar, String, Bytes, Vec, Option, a map, Duration, Timestamp, Uuid, Decimal, or a type declared with #[undra::api] (records, enums) or #[undra::error]; an object (#[undra::api] impl) crosses by handle, never as a value | declare Plain with #[undra::api], or return a record with the data the platform needs; a type of the uuid, chrono, time, rust_decimal or bytes crate crosses once you enable that feature of undra |
() cannot be used as a field | () occupies zero bytes on the wire, so it is only legal as a return type or as a variant without fields; Vec<()>, Option<()> and maps of () defeat length validation | remove the value, or use bool if you need a marker |
DateTime<Local> cannot cross the boundary | a Timestamp is an instant in milliseconds since the Unix epoch, in UTC; a date-time with a local time zone or a fixed offset has no one value every platform reads alike, and the offset itself would be lost | convert to Utc (value.with_timezone(&Utc)) and spell DateTime<Utc>; offsets do not cross |
DateTime<FixedOffset> cannot cross the boundary | a Timestamp is an instant in milliseconds since the Unix epoch, in UTC; a date-time with a local time zone or a fixed offset has no one value every platform reads alike, and the offset itself would be lost | convert to Utc (value.with_timezone(&Utc)) and spell DateTime<Utc>; offsets do not cross |
DerivedList needs the type of its rows | a derived list is a Vec of rows the platforms mirror, so the schema needs the row type, written as the one type argument | write DerivedList<Row> for visible, with the type the pipeline's build() produces |
&str cannot cross the boundary | references have no wire representation; every value crosses by copy | use an owned String |
E0002 generic parameter, or a generic type spelled with its arguments#
Raised by macros.
generic parameter on a #[undra::api] item that is not a template, on an error enum, object, store, function, method, constructor, port, callback, query or mutation (the text of each says what to write instead: #[undra::api(generic)] and a named instantiation for a data type; generic(T = [Todo, Note]), the list of types, for a function or method, ADR-058); a const parameter, a where clause or a default type parameter ("only type parameters are supported"); a generic type spelled with its arguments (Page<Todo>: declare #[undra::api] pub type TodoPage = Page<Todo>; and write TodoPage); the wrong number of type arguments for a template (ADR-042)
| What you see | Why | Fix |
|---|---|---|
Page<Note> has no name (in first_page<Note>) | the schema names every type, and an instantiated generic type is named by the alias that declares it; Page<Note> is reached here by putting a listed type in place of a type parameter, and no alias declares it | declare #[undra::api] pub type NotePage = Page<Note>; next to Page |
generic parameter T on newest has no list of types | the schema describes concrete functions and the platforms call them by id: a generic function crosses once for each type it is declared for, and its callers are on the platforms, where the core cannot see them | list the types the platforms may use: #[undra::api(generic(T = [Todo, Note]))]; each becomes a function of its own, newest<Todo> and newest<Note> |
generic parameter T on pinned has no list of types | the schema describes concrete functions and the platforms call them by id: a generic function crosses once for each type it is declared for, and its callers are on the platforms, where the core cannot see them | list the types the platforms may use: #[undra(generic(T = [Todo, Note]))] on the method; each becomes a method of its own, pinned<Todo> and pinned<Note> |
generic parameter T on the constructor create | a constructor returns the object, and the object has no such parameter: the platforms could not say which create they mean | take a concrete type or an enum of the cases; make the object generic if the parameter belongs to it |
generic parameter T on the store Selection | the schema describes concrete objects: a generic object crosses once per instantiation, each under a name of its own, which the platforms generate a class for | write #[undra::store(generic)], mark its impl block #[undra::api(store, generic)] and declare each instantiation: #[undra::api] pub type TodoSelection = Selection<Todo>; |
generic parameter T on the impl block of Cache | the schema describes concrete objects: a generic object crosses once per instantiation, each under a name of its own, which the platforms generate a class for | mark the block #[undra::api(generic)] (#[undra::api(store, generic)] for a store) and declare each instantiation: #[undra::api] pub type TodoSelection = Selection<Todo>; |
E0003 lifetime in a public signature#
Raised by macros.
lifetime in a public signature
| What you see | Why | Fix |
|---|---|---|
lifetime 'static in &'static str | everything crosses the boundary by value; a borrow cannot outlive the call that made it | use an owned type such as String or Vec<T> |
lifetime 'a on WithLifetime | everything crosses the boundary by value; a borrow cannot outlive the call that made it | remove the lifetime parameter and use owned types |
lifetime 'a in &'a str | everything crosses the boundary by value; a borrow cannot outlive the call that made it | use an owned type such as String or Vec<T> |
lifetime 'a on Label | everything crosses the boundary by value; a borrow cannot outlive the call that made it | remove the lifetime parameter and use owned types |
E0004 a trait object, dyn or impl Trait that is not a callback parameter, or a callback where one may not stand (ADR-041)#
Raised by macros, schema validation (a bound the compiler checks).
trait object / dyn / Box<dyn Fn> / closure / function pointer / an impl Trait that is not a stream (declare a #[undra::callback] trait and take Arc<dyn Trait>, ADR-041); a callback (Arc<dyn Trait>) where one may not stand (anywhere but a parameter of a method, constructor or function, alone or in an Option: a return, a field, a signal, a port or query value), with the help of its position; Arc<dyn Trait> of a trait that is not a #[undra::callback] (the CallbackInterface bound, a branded message)
| What you see | Why | Fix |
|---|---|---|
callback Arc<dyn Listener> cannot be a field of a record or enum (Listener is a callback interface) | a callback is an instance with a lifetime, not a value: it cannot be copied, compared, stored in a record or mirrored from a signal | keep an id or a record here, and take the callback as a parameter of the method that needs it |
callback Arc<dyn Listener> cannot be used here (Listener is a callback interface) | a callback is an object the host implements and passes in for the core to call; the core never hands one out | return a plain value, or an object (Arc<T>) the host can call methods on |
callback Arc<dyn Listener> cannot be used here (Listener is a callback interface) | a callback may be a parameter of a method, constructor or function, alone or in an Option; it cannot be nested in another type | take one Arc<dyn Trait> (or Option<Arc<dyn Trait>>) per parameter |
closure type Arc<dyn Fn(u32) + Send + Sync> cannot cross the boundary | callbacks have no wire representation | declare a #[undra::callback] trait and take Arc<dyn Trait> |
dyn Platform cannot be taken as a callback | only a trait declared with #[undra::callback] has a proxy the core can call and a generated protocol the host implements | add #[undra::callback] to the trait, or pass a record or an id |
dyn Plain cannot be taken as a callback | only a trait declared with #[undra::callback] has a proxy the core can call and a generated protocol the host implements | add #[undra::callback] to the trait, or pass a record or an id |
E0005 Result / Stream outside return position#
Raised by macros, schema validation.
Result or Stream outside return position; a Result<impl Stream<Item = Result<T, E1>>, E2> whose two error types differ (ADR-036)
| What you see | Why | Fix |
|---|---|---|
Result<u32, String> cannot be used as a field | Result<T, E> is how a method reports a typed error; it is only legal as the outermost type of a return | return the Result from the method and keep only plain values in fields, parameters and nested types |
Result<u32, String> cannot be used as a parameter | Result<T, E> is how a method reports a typed error; it is only legal as the outermost type of a return | return the Result from the method and keep only plain values in fields, parameters and nested types |
the items of the stream in Result<impl Stream<Item = Result<u32, ItemError>>, OpenError> fail with ItemError but its opening fails with OpenError | a stream method has one error type: the platforms throw it whether the stream fails to open or ends with an error part-way | use the same #[undra::error] enum for both (OpenError), or one enum with a variant for each case |
Result<u32, String> cannot be nested inside another type | Result<T, E> is how a method reports a typed error; it is only legal as the outermost type of a return | return the Result from the method and keep only plain values in fields, parameters and nested types |
result<u8,named:Oops> at record Todo, field outcome: Result is only allowed as the outermost type of a return | Result<T, E> is how a method reports a typed error, so it has no meaning inside a field, a parameter or another type | return the Result from the method and keep plain values in fields, parameters and nested types |
E0006 map key type not allowed#
Raised by macros, schema validation, a bound the compiler checks.
map key type not allowed: String, integers, bool, Uuid and newtypes of those are keys; a float, a Decimal, a record, a collection, and a newtype of one of those are not (the macros assert K: MapKey at every HashMap/BTreeMap key position, ADR-042)
| What you see | Why | Fix |
|---|---|---|
f64 cannot be a map key | map keys must be String, an integer, bool, Uuid or a newtype of one of those: they compare and hash identically on every platform (floats, decimals, records and collections do not) | use one of those key types, a newtype of one (struct UserId(pub Uuid);), or a Vec of records with an explicit key field |
Decimal cannot be a map key | map keys must be String, an integer, bool, Uuid or a newtype of one of those: they compare and hash identically on every platform (floats, decimals, records and collections do not) | use one of those key types, a newtype of one (struct UserId(pub Uuid);), or a Vec of records with an explicit key field |
undra::prelude::Decimal cannot be a map key | map keys must be String, an integer, bool, Uuid or a newtype of one of those: they compare and hash identically on every platform (floats, decimals, records and collections do not) | use one of those key types, a newtype of one (struct UserId(pub Uuid);), or a Vec of records with an explicit key field |
Loose cannot be a map key | map keys must be String, an integer, bool, Uuid or a newtype of one of those: they compare and hash identically on every platform (floats, decimals, records and collections do not) | use one of those key types, a newtype of one (struct UserId(pub Uuid);), or a Vec of records with an explicit key field |
f32 at record Scores, field by_weight is not a valid map key | map keys must compare and hash the same on every platform: String, an integer type, bool, Uuid and a newtype of one of those do, floats, decimals and composite keys do not | use one of those key types, or a Vec of records with an explicit key field |
decimal at record Prices, field by_amount is not a valid map key | map keys must compare and hash the same on every platform: String, an integer type, bool, Uuid and a newtype of one of those do, floats, decimals and composite keys do not | use one of those key types, or a Vec of records with an explicit key field |
E0007 unsupported item shape or placement of an Undra attribute#
Raised by macros.
unsupported item shape (a unit struct, a tuple struct of two or more fields or none (one field is a newtype), a record without fields, a type alias that does not name an instantiation of a #[undra::api(generic)] type, an empty enum, an impl item that is neither a method nor a constructor, a receiver that is not &self, a store that is not a struct with named fields, the reserved field name __undra_cell, #[undra::port] on an inherent impl, an Undra attribute on the wrong kind of item, #[undra::api] on a method, #[undra::query] or #[undra::mutation] inside an impl block or a port trait, a function whose signature uses Self, a second #[undra::api] impl block for one type). A second impl block is reported by rustc as "the name _undra_error_E0007_<Type>_has_two_undra_api_impl_blocks_merge_them_into_one is defined multiple times": merge the blocks. A query or mutation inside an impl block that is not #[undra::api] cannot be seen by its macro; rustc then reports "macro definition is not supported in traits or impls" and "cannot find macro _undra_error_E0007_a_query_is_a_free_function_move_it_out_of_the_impl_block", which is this code: move the function out of the block
| What you see | Why | Fix |
|---|---|---|
#[undra::api] on new, which is an associated function: its signature uses Self | Self only exists inside an impl block, and #[undra::api] on a function exposes a free function; the functions of an object are exposed by putting the attribute on the impl block they are in | remove #[undra::api] from new and write #[undra::api] above the impl block (it exposes every pub fn in it) |
#[undra::query] on the method forecast of a port trait | a port is a list of methods the platform implements; the attribute applies to a whole item (a type or a free function), never to a trait method | remove the attribute from forecast; a #[undra::query] is a free async fn(ctx: &Ctx, ..) that calls the port as weather(ctx).forecast(..), so write it outside the trait |
#[undra::api] on the method now of a port trait | a port is a list of methods the platform implements; the attribute applies to a whole item (a type or a free function), never to a trait method | remove the attribute from now; a function the core exposes that calls the port is a free #[undra::api] fn(ctx: &Ctx, ..) outside the trait, calling weather(ctx).now(..) |
#[undra::query] on admins, which is inside an impl block: its signature uses Self | a query is a free function, and the macro generates a struct next to it, which an impl block cannot hold | move admins out of the impl block, to module level, and spell out the type instead of Self |
#[undra::store] cannot be applied to an enum | #[undra::store] applies to a struct | move #[undra::store] onto a struct, or remove it |
#[undra::api] on the type alias Alias, which does not name an instantiation | a type alias is not a schema type of its own; the only alias that is names an instantiation of a generic data type declared with #[undra::api(generic)], so it can be given a name the platforms generate a type for | write #[undra::api] pub type Alias = Page<Todo>; for a template Page, or remove #[undra::api] and write the aliased type where it is used |
E0008 unknown or misplaced #[undra(..)] attribute or macro argument#
Raised by macros.
unknown or misplaced #[undra(..)] attribute or macro argument (an unknown key, with the nearest name suggested, a value of the wrong kind or a value on a flag, key on a signal that is not a Signal<Vec<T>> or a DerivedList<T> (a keyed Computed is pointed at DerivedList<T>), a DerivedList<T> without key (ADR-039), key naming no field of the list's items (for a generic store: of the row type of one instantiation, at its alias), generic on a type, an impl block or a store that has no type parameter, generic(..) with a list on a struct, an enum or an impl block (a list instantiates a function; a type is instantiated by an alias, ADR-058), generic alone on a function, a malformed list, #[cfg] on a public item, an invalid crate = ".." path); a cfg_attr whose attributes are all documentation or lint levels is accepted
| What you see | Why | Fix |
|---|---|---|
#[undra(key = "idd")] on typo names no field of Row | key names the field of the list's items that identifies them, and Row has the fields id, title | write the name of one of those fields as the key |
#[undra(key = "n")] on not_a_record names no field of u32 | key names the field of the list's items that identifies them, and u32 has no fields (only a record declared with #[undra::api] has any) | write the name of one of those fields as the key |
#[undra(key = "not a name")] on not_a_name names no field of Tagged | key names the field of the list's items that identifies them, and Tagged has the fields type, id | write the name of one of those fields as the key |
unknown option defualt in #[undra(..)] | the options are crate = "path" (items), default (record fields), key = "field" and no_coalesce (store signal fields), coalesce (fire-and-forget methods of a callback interface) and generic(T = [..]) (methods with a type parameter) | did you mean default? Otherwise remove defualt |
unknown option frobnicate in #[undra(..)] | the options are crate = "path" (items), default (record fields), key = "field" and no_coalesce (store signal fields), coalesce (fire-and-forget methods of a callback interface) and generic(T = [..]) (methods with a type parameter) | remove frobnicate, or use one of: crate, default, key, no_coalesce, coalesce, generic |
#[undra(key)] is not valid on a record or variant field | key = "field" turns a store's Signal<Vec<T>> into a keyed list that ships patches | move it to a Signal<Vec<T>> field of a #[undra::store] struct, or remove it |
Errors and stores#
E0010 invalid #[undra::error] variant#
Raised by macros, schema validation.
#[undra::error] variant without #[error(..)], a message with an implicit {} (write {0} or {name}), #[error], #[from] or #[source] on a plain #[undra::api] enum
| What you see | Why | Fix |
|---|---|---|
variant NotFound has no #[error(..)] message | every variant of a #[undra::error] enum needs a message, because the platforms show it to users and logs | add #[error("what went wrong")], or #[error(transparent)] to forward to the inner error |
invalid message for variant Missing: {1} refers to field 1, but the variant has 1 | the message is a template over the variant's fields | use {0}, {1}, .. for tuple fields and {name} for named fields |
#[error(transparent)] on variant Both needs exactly one field, found 2 | transparent forwards Display and source() to the variant's only field | give the variant a single field holding the inner error |
#[error] on the variant A belongs to #[undra::error], not #[undra::api] | #[error(..)], #[from] and #[source] are the helper attributes of error enums; a plain #[undra::api] enum has no messages, Display or From impls | change the enum's attribute to #[undra::error], or remove the helper attribute |
#[from] on the field 0 belongs to #[undra::error], not #[undra::api] | #[error(..)], #[from] and #[source] are the helper attributes of error enums; a plain #[undra::api] enum has no messages, Display or From impls | change the enum's attribute to #[undra::error], or remove the helper attribute |
variant Unmessaged has no #[error(..)] message | every variant of a #[undra::error] enum needs a message, because the platforms show it to users and logs | add #[error("what went wrong")], or #[error(transparent)] to forward to the inner error |
E0011 store and #[undra::api(store)] impl block disagree#
Raised by macros, schema validation.
#[undra::store] and its #[undra::api(store)] impl block disagree, including a store with no impl block and a #[undra::api(store)] block without a constructor (a type takes one block; a constructor in another block is not seen); a store without a constructor in the schema; for a generic store (ADR-058) the impl block below its struct in the same module: a block that is not below a #[undra::store(generic)] struct is reported by rustc as "cannot find macro _undra_error_E0011_<Type>_is_not_a_generic_store_declared_above_this_impl_block_in_the_same_module", a #[undra::store(generic)] whose block is #[undra::api(generic)] without store by a const assertion at the alias, and a #[undra::store(generic)] with no generic block at all by "cannot find macro Selection in this scope ... Selection is in scope, but it is a struct, not a macro": write the block
| What you see | Why | Fix |
|---|---|---|
store Counter has no constructor in this #[undra::api(store)] block | the platforms create a store by calling one of its constructors, and a type takes one #[undra::api] impl block, so a constructor in another block is not seen | add pub fn new(ctx: Ctx) -> Self to this block; if Counter has a second #[undra::api] block (where the constructor is), move this block's methods into that one |
Selection is a #[undra::store(generic)] but its impl block is not marked as a store | the impl block of a store must say so, so its constructors can attach the store's signals and its struct literals get the hidden cell field | write #[undra::api(store, generic)] on the impl block |
Todos is a #[undra::store] but its #[undra::api] impl block is not marked as a store | the impl block of a store must say so, so its constructors can attach the store's signals and its struct literals get the hidden cell field | write #[undra::api(store)] on the impl block |
Plain is implemented with #[undra::api(store)] but the struct has no #[undra::store] | the store marker wires the constructors to the struct's signals, which only #[undra::store] sets up | add #[undra::store] to struct Plain, or remove store from the impl attribute |
store Todos has no #[undra::api(store)] impl block | the constructors of the impl block create the store and wire its signals to the platforms; without the block the store can never be instantiated | add an impl Todos block marked #[undra::api(store)] with a constructor such as pub fn new(ctx: Ctx) -> Self |
store Counter has no constructor | the platforms create a store by calling one of its constructors; without one it can never be instantiated | add pub fn new(ctx: Ctx) -> Self to its #[undra::api(store)] impl block |
E0012 trait object in a record field#
Raised by macros.
trait object in a record field (the blueprint example)
| What you see | Why | Fix |
|---|---|---|
Vec<Box<dyn Any>> cannot cross the boundary | trait objects have no wire representation | make items a concrete #[undra::api] type, or an enum listing the cases you need |
E0013 store cannot be restored automatically#
Raised by macros.
store cannot be restored automatically: it has a Computed field, or a field that is neither a signal, a Ctx, a WeakCtx nor Default, and no #[undra::store(restore = "..")] hook
| What you see | Why | Fix |
|---|---|---|
store Todos cannot be restored automatically: count is computed | restoring a snapshot decodes the plain signals and rebuilds the store, but only your code knows how to derive computed signals from them | add #[undra::store(restore = "Self::rebuild")] with fn rebuild(ctx: Ctx, <one Signal<T> per plain signal, in order>) -> Self, the same code new uses to build the store |
store Sync cannot be restored automatically: its field of type Config has no Default | restoring a snapshot rebuilds the store from its plain signals and fills every other field with Default::default() (a Ctx is cloned from the argument, a WeakCtx downgraded from it) | implement Default for the type, or add #[undra::store(restore = "Self::rebuild")] with fn rebuild(ctx: Ctx, <one Signal<T> per plain signal, in order>) -> Self, the same code new uses to build the store |
Methods#
E0020 &mut self receiver#
Raised by macros.
&mut self receiver
| What you see | Why | Fix |
|---|---|---|
&mut self receiver on method clear | objects are shared as Arc<Type> across calls and threads, so methods only ever get &self | take &self and mutate through signals (Signal<T>), a Mutex or another form of interior mutability |
&mut self receiver on method increment | objects are shared as Arc<Type> across calls and threads, so methods only ever get &self | take &self and mutate through signals (Signal<T>), a Mutex or another form of interior mutability |
E0021 self by value#
Raised by macros.
self by value
| What you see | Why | Fix |
|---|---|---|
self by value on method finish | an object is shared across calls; a method cannot consume it | take &self and clone whatever you need to keep |
E0022 non-Send future in an async method: rustc's own error, pointed at the method by an assertion named after this code#
Raised by rustc, named by a macro.
non-Send future in an async method or query: rustc's own "future cannot be sent between threads safely", pointed at the method by an assertion the macros emit; the last note names the assertion, _undra_error_E0022_the_future_of_an_async_method_must_be_Send. Do not hold a non-Send value (an Rc, a RefCell borrow, a MutexGuard) across an .await
The compiler reports this one itself, so it carries no Undra code. It is pointed at the method, and the last note names the assertion the macro emitted, _undra_error_E0022_the_future_of_an_async_method_must_be_Send: the code to look up.
error: future cannot be sent between threads safely
--> src/lib.rs:15:18
|
15 | pub async fn run(&self) -> u32 {
| ^^^ future created by async block is not `Send`
|
= help: within `{async block@src/lib.rs:9:1: 9:10}`, the trait `Send` is not implemented for `Rc<u32>`
note: future is not `Send` as this value is used across an await
--> src/lib.rs:17:32
|
16 | let local = Rc::new(1_u32);
| ----- has type `Rc<u32>` which is not `Send`
17 | std::future::ready(()).await;
| ^^^^^ await occurs here, with `local` maybe used later
note: required by a bound in `_undra_error_E0022_the_future_of_an_async_method_must_be_Send`
--> src/lib.rs:9:1
|
9 | #[k::api]
| ^^^^^^^^^ required by this bound in `_undra_error_E0022_the_future_of_an_async_method_must_be_Send`
= note: this error originates in the attribute macro `k::api` (in Nightly builds, run with -Z macro-backtrace for more info)Ports#
E0030 port method with a non-wire parameter#
Raised by macros.
port method with a non-wire parameter
| What you see | Why | Fix |
|---|---|---|
parameter listener of port method call is not a wire type | callback Arc<dyn Listener> cannot be a parameter of a port (Listener is a callback interface) (a port is implemented once, by the platform, for the whole process; a callback instance in its arguments would need a wrapper type the port implementation does not have) | pass a record or an id through the port |
parameter url of port method request is not a wire type | &str cannot cross the boundary (references have no wire representation; every value crosses by copy) | use an owned String |
parameter on_progress of port method request is not a wire type | trait object dyn Fn(u8) cannot cross the boundary (trait objects have no wire representation and no equivalent in Swift, Kotlin or TypeScript) | use a concrete #[undra::api] type or an enum listing the cases you need; to call into the platform, declare a #[undra::callback] trait and take Arc<dyn Trait> as a parameter |
parameter child of port method open is not a wire type | object Arc<Child> cannot be a parameter of a port (a port implementation on the platform would receive a reference it has no wrapper type for) | pass a record or an id through the port (the object here is Child) |
E0031 event port method that is not a plain fn(..) returning ()#
Raised by macros, schema validation.
event port method with a return type, or that is async
| What you see | Why | Fix |
|---|---|---|
event port method changed returns a value | events are fire-and-forget notifications from the host; there is no reply to carry a value | remove the return type, or drop event from #[undra::port(event)] to make it a request/reply port |
event port method resumed is async | events are fire-and-forget notifications from the host; nothing waits for them | make it a plain fn returning () |
event port Connectivity method changed returns a value or is async | events are fire-and-forget notifications from the host; nothing waits for them, so there is no reply to carry a value | make the method a plain fn returning (), or make the port a request/reply port |
E0032 invalid port trait shape#
Raised by macros.
invalid port trait shape (an async method on a sync port, a parameter that is not a plain name, an associated type or const, no &self receiver)
| What you see | Why | Fix |
|---|---|---|
#[undra::port(sync)] port has the async method now_ms | sync promises that every method answers immediately, so the core can call it without yielding | remove async, or remove sync from the attribute |
port trait Kv has an associated item that is not a method | a port is a list of methods the platform implements; associated types and constants have no wire representation | remove it, or move it to a separate trait |
E0033 the error type of a port method has no From<PortError>#
Raised by macros (a bound the compiler checks).
the error type of a Result port method has no From<PortError> (an unavailable port cannot be reported)
| What you see | Why | Fix |
|---|---|---|
the error type StoreError of a method of the Store port cannot represent a port that is unavailable | a port nobody registered, a cancelled call and a reply that does not decode are ordinary outcomes (SPEC 6.3), and a method that returns Result<T, E> reports them as its error instead of panicking; that needs From<PortError> for the error type | implement From<undra::runtime::PortError> for StoreError, mapping it to a variant such as Unavailable, or to the Display text of the PortError |
Queries and mutations#
E0040 query without key, mutation with stale, or another invalid query argument#
Raised by macros.
query without key / mutation with stale / a query argument of the wrong kind, an interval below one second (use a stream for real-time data), refetch_pages or persist_pages that is not a whole number of at least 1, polling or paging options on a mutation
| What you see | Why | Fix |
|---|---|---|
interval = "500ms" is below one second | a poll fetches the whole result again each time, so a query polled more than once a second is really a stream: use a stream for real-time data | write interval = "1s" or more, or deliver the changes with a #[undra::port] event or a stream |
interval = "0s" is below one second | a poll fetches the whole result again each time, so a query polled more than once a second is really a stream: use a stream for real-time data | write interval = "1s" or more, or deliver the changes with a #[undra::port] event or a stream |
invalid interval duration: soon does not start with a whole number | interval is how long after a fetch ends the next one starts | write a whole number and a unit, for example interval = "30s" |
mutation add has interval | polling and paging apply to cached reads; a mutation writes and caches nothing | remove interval; put it on the query the mutation invalidates |
query todos has no key | the cache is addressed by key: two calls share a cached result only if their keys are equal | add key = "todos", with {param} placeholders for the parameters that distinguish results |
mutation add_todo has stale | stale is how long a cached *read* stays fresh; a mutation writes and caches nothing | remove stale; put it on the query the mutation invalidates |
E0041 query or mutation function with an invalid signature#
Raised by macros.
query or mutation function with an invalid signature (not async, no ctx: &Ctx first parameter, not returning Result<T, E>, a stream result, self)
| What you see | Why | Fix |
|---|---|---|
sync_query must be async | #[undra::query] functions fetch or write through ports, which are asynchronous | write async fn |
no_ctx must take ctx: &Ctx as its first parameter | the runtime hands every query and mutation a context to reach ports and other queries | add ctx: &Ctx (or ctx: Ctx) before the other parameters |
plain must return Result<T, E> | the cache stores the success value and the error separately, and the platforms show both | return Result<T, E> where E is a #[undra::error] enum |
E0042 query whose success value is () or an Option#
Raised by macros.
query whose success value is () or an Option (a query caches a value; use a mutation for effects)
| What you see | Why | Fix |
|---|---|---|
query ping returns () | a query caches the value it returns; a query with nothing to return has nothing to cache | use #[undra::mutation] for a call that only has effects, or return the data the platform needs |
query find returns an Option | the handle's data signal is already optional (no result yet), so an optional result would be ambiguous: None could mean "not loaded" or "loaded, absent" | return a record or a list (an empty Vec says "nothing"), or an enum naming the cases |
Names in the generators#
E0050 duplicate type name, id or variant index#
Raised by schema validation.
duplicate type name, a type named like something the generated code depends on, two items with one id, two variants with one index
| What you see | Why | Fix |
|---|---|---|
duplicate type name Todo (declared as record and again as enum) | type names must be unique within a core: a type is identified to the platforms by its name (its id is a hash of it), so two declarations cannot share one | rename one of the two Todo declarations, or remove the duplicate |
duplicate type name Storage at the port Storage (the name is already used by a record) | names and ids identify a type, a method or a variant to the platforms and in the generated code, so each must be unique within a core | rename one of the two, or remove the duplicate |
record Signal has a name the generated code depends on | the generated bindings use a type called Signal (a standard type of Swift, Kotlin or TypeScript, or one of the Undra runtime's), so a type of the schema with the same name would shadow it | rename it, for example MySignal |
duplicate type id 0x00000007 at the schema (Alpha and Beta hash to the same id) | names and ids identify a type, a method or a variant to the platforms and in the generated code, so each must be unique within a core | rename one of the two items: ids are hashes of the names, so a different name gives a different id |
duplicate variant index 1 at enum Status | names and ids identify a type, a method or a variant to the platforms and in the generated code, so each must be unique within a core | give every variant of the enum an index of its own |
duplicate type name Todo (declared as record and again as record) | type names must be unique within a core: a type is identified to the platforms by its name (its id is a hash of it), so two declarations cannot share one | rename one of the two Todo declarations, or remove the duplicate |
E0051 a name that collides after case conversion or is not an identifier#
Raised by schema validation.
a name that collides after case conversion (a_b and aB), shadows a member of the runtime base classes, or is not an identifier in a target language; in the iOS 15 / 16 Swift mode also a store member named objectWillChange (§10.1, ADR-045)
| What you see | Why | Fix |
|---|---|---|
at record Todo, due_date, dueDate all become dueDate | field names are converted to camelCase, so names that differ only in case or underscores end up equal | rename one of them so that they stay distinct after conversion |
at object Thing, close is a name the generated code already uses | the runtime base class or the generated code already declares a member with that name | rename it so that it does not meet that name |
at record Todo, 1st is not a name the generated code can use | every name of the schema becomes an identifier in Swift, Kotlin and TypeScript: ASCII letters, digits and underscores, not starting with a digit | rename it to letters, digits and underscores, starting with a letter |
at object Counter, object_will_change becomes objectWillChange, a name the generated code already uses | with the iOS 15 / 16 store shape (swift_observation = "observable-object", the default for a deployment target below iOS 17) a store is a Combine ObservableObject, which declares that member itself | rename it so that it does not meet that name |
at the schema, newest<Todo>, newest_todo all become newestTodo | id constants are named in camelCase in Swift and TypeScript, and the id of an instantiation of a generic function names the function and the type, so names that differ only in case or underscores end up equal | rename one of them so that they stay distinct after conversion |
at the schema, newest<Todo>, newest_todo all become NEWEST_TODO | id constants are named UPPER_SNAKE_CASE in Kotlin, and the id of an instantiation of a generic function names the function and the type, so names that differ only in case or underscores end up equal | rename one of them so that they stay distinct after conversion |
E0052 an item named like a standard library item, with another id#
Raised by schema validation.
a record, enum, error, object or port named like a standard library item (section 8) but with another id: the runtimes implement the standard items under those names and ids
| What you see | Why | Fix |
|---|---|---|
record HttpRequest has the name of an Undra standard library item but the id 0x00000007 instead of 0xbbbc6e52 | every platform runtime implements the standard ports and types under those names and ids, and generated code refers to them instead of declaring them, so a different item cannot share the name | rename it, for example MyHttpRequest, or use the standard one from undra-ports |
Type identity and the schema#
E0060 a spelling that looks like a built-in Undra type is another type#
Raised by macros (a check the compiler runs).
a spelling that looks like a built-in Undra type (Bytes, Uuid, String, Vec, ..) is a different type; reported at the field or parameter by the same-type assertion the macros emit; for a wire leaf (Uuid, Timestamp, Duration, Bytes, Decimal) by the membership assertion Spelled: WireLeaf<kind>, whose message names the leaves and the features (uuid, chrono, time, rust_decimal, bytes) that add the types of other crates (ADR-042)
| What you see | Why | Fix |
|---|---|---|
Bytes is spelled like a built-in Undra type, but it is not one | the schema records this position as a wire leaf (Uuid, Timestamp, Duration, Bytes or Decimal), so the platforms would read the bytes of that leaf where the generated code writes Bytes | rename your type, import the built-in one, or, for a type of the uuid, chrono, time, rust_decimal or bytes crate, enable that feature of undra |
Uuid is spelled like a built-in Undra type, but it is not one | the schema records this position as a wire leaf (Uuid, Timestamp, Duration, Bytes or Decimal), so the platforms would read the bytes of that leaf where the generated code writes Uuid | rename your type, import the built-in one, or, for a type of the uuid, chrono, time, rust_decimal or bytes crate, enable that feature of undra |
Timestamp is spelled like a built-in Undra type, but it is not one | the schema records this position as a wire leaf (Uuid, Timestamp, Duration, Bytes or Decimal), so the platforms would read the bytes of that leaf where the generated code writes Timestamp | rename your type, import the built-in one, or, for a type of the uuid, chrono, time, rust_decimal or bytes crate, enable that feature of undra |
Decimal is spelled like a built-in Undra type, but it is not one | the schema records this position as a wire leaf (Uuid, Timestamp, Duration, Bytes or Decimal), so the platforms would read the bytes of that leaf where the generated code writes Decimal | rename your type, import the built-in one, or, for a type of the uuid, chrono, time, rust_decimal or bytes crate, enable that feature of undra |
E0061 the name written is not the declared name of the type, or the type is not declared with #[undra::api]#
Raised by macros (a check the compiler runs).
the schema records a name that the type written there does not have: an alias of an Undra type (type Todo = Item), a renamed import (use m::Item as Todo), or a name that is not a type declared with #[undra::api] at all (a plain struct, type Id = u64); reported by a const assertion on UNDRA_TYPE_ID
| What you see | Why | Fix |
|---|---|---|
Plain is not a type declared with #[undra::api] | Undra describes a type to the platforms by the name it is written with, so the name must be a record or enum declared with #[undra::api] or an error declared with #[undra::error]; anything else, such as a plain struct or an alias (type Id = u64), has no definition the platforms could generate | add #[undra::api] to Plain, or, if it is an alias, write the type it stands for where it is used |
Id is not a type declared with #[undra::api] | Undra describes a type to the platforms by the name it is written with, so the name must be a record or enum declared with #[undra::api] or an error declared with #[undra::error]; anything else, such as a plain struct or an alias (type Id = u64), has no definition the platforms could generate | add #[undra::api] to Id, or, if it is an alias, write the type it stands for where it is used |
Kid here is an alias or a renamed import of an object that is declared under another name | Undra describes an object to the platforms by the name it is written with, while the handle the core issues is of the type that name resolves to; with type Kid = Other or use path::Other as Kid the platforms would wrap it as Kid | write the object under the name it is declared with (Other in the examples above) |
LostPage here is an alias or a renamed import of an Undra type that is declared under another name | Undra describes a type to the platforms by the name it is written with, while the generated code encodes the type that name resolves to; with type LostPage = Other or use path::Other as LostPage the platforms would be told LostPage and receive the layout of Other | write the type under the name it is declared with (Other in the examples above), or declare a separate #[undra::api] struct LostPage if you mean a distinct type |
Todo here is an alias or a renamed import of an Undra type that is declared under another name | Undra describes a type to the platforms by the name it is written with, while the generated code encodes the type that name resolves to; with type Todo = Other or use path::Other as Todo the platforms would be told Todo and receive the layout of Other | write the type under the name it is declared with (Other in the examples above), or declare a separate #[undra::api] struct Todo if you mean a distinct type |
Entry here is an alias or a renamed import of an Undra type that is declared under another name | Undra describes a type to the platforms by the name it is written with, while the generated code encodes the type that name resolves to; with type Entry = Other or use path::Other as Entry the platforms would be told Entry and receive the layout of Other | write the type under the name it is declared with (Other in the examples above), or declare a separate #[undra::api] struct Entry if you mean a distinct type |
E0062 a port call could not be answered and its method has no error channel: a runtime message#
Raised by runtime (the generated port proxy).
a port call that cannot be answered and has no error channel: no adapter registered, a cancelled call, a reply that does not decode. A method without an error channel panics with this message (the runtime contains the panic at the dispatch boundary; on wasm it traps the core); a method returning Result reports it as its error type, and HttpError::Network / FsError::Io carry the code and the link
| What you see | Why | Fix |
|---|---|---|
the Rng port has no adapter registered (method fill) | this method has no error channel, so an unavailable port cannot be reported and the call panics; the runtime contains the panic, but on the web it traps the core | register an adapter (core.registerPort(..) in TypeScript, Kotlin and Swift, undra_port_register in C), bind a Rust implementation (undra::ports::fakes in tests), or give the method a Result<T, E> return type so it can report the outage |
E0063 nested Option<Option<T>>#
Raised by macros.
Option<Option<T>> in a public position
| What you see | Why | Fix |
|---|---|---|
nested option Option<Option<u8>> cannot cross the boundary | Kotlin and TypeScript cannot express nested optionality: Some(None) and None would both arrive as null | wrap the inner option in a record or an enum that names the two cases |
nested option Option<Option<i32>> cannot cross the boundary | Kotlin and TypeScript cannot express nested optionality: Some(None) and None would both arrive as null | wrap the inner option in a record or an enum that names the two cases |
nested option Option<Box<Option<u8>>> cannot cross the boundary | Kotlin and TypeScript cannot express nested optionality: Some(None) and None would both arrive as null | wrap the inner option in a record or an enum that names the two cases |
E0064 an object (#[undra::api] impl) used where a value is expected, or a value used as an object, or an object where objects may not stand (ADR-040)#
Raised by macros (a check the compiler runs), schema validation.
an object (#[undra::api] impl) used as a value (a field, a parameter or a return written Mailbox): it crosses as Arc<Mailbox> or &Mailbox; a record, enum or error written as an object (Arc<Todo>, &Todo: records cross by value); an object where objects may not stand (a record or variant field, a signal, a map key or value, a stream item, a port, callback, query or mutation value, or nested deeper than Option or Vec), with the reason and the way out of its position (ADR-040)
| What you see | Why | Fix |
|---|---|---|
Calculator is an object and cannot be used as a value | an object lives in the core and crosses the boundary as a handle; its contents have no wire representation, so it cannot be a field, a variant field, a signal value, a map entry or a query value | return it as Arc<Calculator>, take it as &Calculator or Arc<Calculator> (a method, constructor or function parameter or return), or use a record with the data the platform needs |
NotAnObject is not an object | an object is a type with an #[undra::api] impl block: the macro generates what lets the core hand it to the platforms as a handle, and without one there is nothing to hand out | add #[undra::api] to an impl NotAnObject { .. } block, or use a record (#[undra::api] struct) if it is plain data |
object Arc<Child> cannot be a field of a record or enum | a record or enum field holds a value: it is copied, compared, hashed and Codable, and none of that can carry a reference to an object | keep the data the platform needs in the field (an id, a record), and put the child object behind a method of the parent (the object here is Child) |
object Arc<Child> cannot be used here | an object can only stand alone, or inside Option or Vec, as a method or function parameter or return | use Arc<T>, Option<Arc<T>> or Vec<Arc<T>> (a parameter may also be &T or Option<&T>) (the object here is Child) |
&Child cannot be an element of a list | a list owns its elements, and a borrow of an object cannot outlive the call that made it | write the list as Vec<Arc<Child>> |
object Arc<Child> cannot be the result of a query or mutation | query and mutation values are cached, compared and persisted, so they must be values | use a record or an id, and return the object from a method that calls the query (the object here is Child) |
E0065 a signal of a store written off its owning runtime's core (ADR-035): a runtime message#
Raised by runtime (the write check of undra-signals).
a signal of a store was written from a thread that does not hold the owning runtime's core lock: a blocking-pool worker, a host or embedder thread, a thread inside no runtime, or another runtime's core. A panic with this message, in every build; Signal::try_set / try_update return it as WriteError::OffCore (ADR-035)
| What you see | Why | Fix |
|---|---|---|
| a signal of a store owned by runtime 5 was written from a thread that does not hold its core lock | signal writes belong on the core: the runtime delivers each change-set to its host in commit order under its core lock, so a write from any other thread (a blocking-pool worker, a host or embedder thread, another runtime's core) would be delivered unordered, to the wrong host, or not at all | return the value to the task or call that awaits it (ctx.spawn, a dispatched call, the result of spawn_blocking), or wrap the write in ctx.with_core(|| ..) on a host thread; Signal::try_set reports this as a WriteError instead of panicking |
E0066 a #[undra::migrate] hook with a wrong target or shape (ADR-037; addition)#
Raised by macros, runtime (start-up check of the registered hooks).
a #[undra::migrate] hook with a wrong target or shape (ADR-037): no target or more than one, signal without store, a from that is not a 64-bit hex fingerprint, a function that is not a plain non-generic fn taking the target's old value (&DynValue, Option<&DynValue> or &DynRecord) and returning Result<_, MigrateError>, a ty = "X" hook that does not return the #[undra::api] type X (a const assertion the compiler runs); a store, signal or mutation the core does not have, or a signal hook returning another type than the signal's, is logged at ERROR with this code when a runtime starts (the macro cannot see those items)
| What you see | Why | Fix |
|---|---|---|
#[undra::migrate] needs a target | a migration hook converts persisted data of one record or enum, one signal of one store, or one mutation's queued input to this build's types; the runtime finds it by that target and calls it with the old value in a fixed shape | name exactly one target: ty = "Todo", store = "Profile", signal = "age" or mutation = "add_todo" |
#[undra::migrate] names more than one target | a migration hook converts persisted data of one record or enum, one signal of one store, or one mutation's queued input to this build's types; the runtime finds it by that target and calls it with the old value in a fixed shape | name exactly one target: ty = "Todo", store = "Profile", signal = "age" or mutation = "add_todo" |
signal = ".." needs store = ".." | a migration hook converts persisted data of one record or enum, one signal of one store, or one mutation's queued input to this build's types; the runtime finds it by that target and calls it with the old value in a fixed shape | name the store the signal belongs to: store = "Profile", signal = "age" |
the migration hook wrong_parameter must take one parameter, old: Option<&DynValue> | a migration hook converts persisted data of one record or enum, one signal of one store, or one mutation's queued input to this build's types; the runtime finds it by that target and calls it with the old value in a fixed shape | write fn wrong_parameter(old: Option<&DynValue>) -> Result<T, MigrateError>, where T is the signal's value type (old is None when the snapshot lacks the signal): a plain, non-generic, non-async function |
the migration hook wrong_return must return Result<DynRecord, MigrateError> | a migration hook converts persisted data of one record or enum, one signal of one store, or one mutation's queued input to this build's types; the runtime finds it by that target and calls it with the old value in a fixed shape | write fn wrong_return(old: &DynRecord) -> Result<DynRecord, MigrateError>: a plain, non-generic, non-async function |
from = "not-hex" is not a fingerprint | a migration hook converts persisted data of one record or enum, one signal of one store, or one mutation's queued input to this build's types; the runtime finds it by that target and calls it with the old value in a fixed shape | write the 64-bit fingerprint of the old type in hex, as the runtime's log or undra.types.<fingerprint> key shows it: from = "0x0123456789abcdef", or leave from out to take every old version |
E0070 a named instantiation of a generic data type that is declared twice or outside the crate of its template#
Raised by macros (a check the compiler runs).
a named instantiation of a generic data type, object or store (type TodoPage = Page<Todo>, type TodoSelection = Selection<Todo>) declared twice, or outside the crate of its template (ADR-042, ADR-058; for an object or a store a module-level constant _undra_error_E0070_this_instantiation_of_Selection_Todo_is_declared_twice_keep_one_alias_per_instantiation makes a second alias in the same module the first error rustc reports): the inherent impl of the instantiation carries a constant named after the rule (_undra_error_E0070_this_instantiation_of_Page_is_declared_twice_keep_one_alias_per_instantiation), so a second alias of one instantiation is reported by rustc as that constant defined twice; an alias in another crate than its template's is reported by the macro itself, naming both crates
| What you see | Why | Fix |
|---|---|---|
TodoPage instantiates Page, which is declared in the crate model, not in app | an instantiation adds an inherent impl to the template's type, which only the crate that declares the template may do, and a second crate naming the same instantiation would register it twice | declare the alias next to the template, in model, and use it from here; or declare a concrete #[undra::api] struct or enum in this crate |
E0071 a method of a #[undra::callback] trait that is neither fire-and-forget nor async with a Result, or whose name starts with __ (ADR-041)#
Raised by macros, schema validation.
a method of a #[undra::callback] trait that returns a value synchronously, is async without a Result, whose name starts with __ (reserved for __release and __cancel), or an async method marked #[undra(coalesce)] (ADR-041): the host runs a callback outside the core's thread and lock, so the core can never wait for it, and a host can always fail or be gone; a method reports (fn m(&self, ..)) or is async and returns Result<T, E>
| What you see | Why | Fix |
|---|---|---|
callback method token returns a value synchronously | the host runs a callback outside the core's thread and lock, so the core can never wait for it synchronously, and a host implementation can always fail or be gone | make it async and return Result<T, E>, or make it a plain fn that returns nothing |
callback method ask is async and returns nothing | the host runs a callback outside the core's thread and lock, so the core can never wait for it synchronously, and a host implementation can always fail or be gone | return Result<T, E> (an #[undra::error] enum that implements From<PortError>), or remove async to make it a fire-and-forget report |
callback method count is async but does not return a Result | the host runs a callback outside the core's thread and lock, so the core can never wait for it synchronously, and a host implementation can always fail or be gone | return Result<T, E> so the method can report that the host failed or is gone |
#[undra(coalesce)] on the async callback method confirm | coalesce drops the older of two pending calls, and an async method's caller is waiting for each answer | remove #[undra(coalesce)], or make the method a plain fn that reports progress |
callback method __release has a reserved name | names that start with __ belong to the protocol (__release gives an instance back, __cancel cancels a call): a method of that name would be mistaken for one | rename the method |
method token of the callback interface Provider returns a value synchronously: make it async and return a Result<T, E> | the host runs a callback outside the core's thread and lock, so the core can never wait for it synchronously, and a host implementation can always fail or be gone: a method either reports (fire-and-forget, returning nothing) or is async and returns a Result | make a reporting method return (), or make a method that answers async and return Result<T, E>; do not start a name with __ |
E0072 the instantiation list of a generic function or method (generic(T = [Todo, Note])) is empty, repeats a type, lists something that is not a named value type, names a type parameter the function does not have, or the function has several type parameters; a schema whose generic labels do not describe their definitions (ADR-058; addition)#
Raised by macros, schema validation.
the instantiation list of a generic function or method (ADR-058): a list for a parameter the function does not have, an empty list, a type listed twice, a type that is not a named value type (Vec<Todo>, a scalar, String, a leaf type, Arc<Mailbox>, an object: a const assertion the compiler runs says so for a plain name that turns out to be an object), a function with two type parameters; in the schema a generic label that does not describe its definition (the name is not of<Type>, the argument is not a record or an enum of the schema, a constructor or port method carries a label) or definitions that share one of but are not one function with one type replaced (a different parameter list, is_async, takes_ctx, inferred flag, parameter name or type shape with the names erased)
| What you see | Why | Fix |
|---|---|---|
generic(U = [..]) on wrong_parameter, which has no type parameter U | the list says which types a type parameter of the function is instantiated with; wrong_parameter declares T | write generic(T = [Todo, Note]) |
generic(T = [..]) on no_parameter, which has no type parameter T | the list says which types a type parameter of the function is instantiated with; no_parameter declares none | remove generic(..), or add the type parameter |
the list of T on empty is empty | a generic function crosses once per listed type; with no type it would not cross at all | list at least one type, generic(T = [Todo]), or remove #[undra::api] if the function is not for the platforms |
Todo is listed twice for T on repeated | each listed type becomes one function, repeated<Todo>, and two functions cannot share that name | remove one of them |
Vec<Todo> cannot be listed for T on unnamed | each instantiation is presented under the name of its type (draft(Todo.self) in Swift, draft(Todo::class) in Kotlin, draft("Todo") in TypeScript), so a listed type is a value type declared with #[undra::api]: a record, an enum, a newtype or a named instantiation | list the element type and write Vec<T> in the signature, or give the type a name: #[undra::api] pub struct Todos(pub Vec<Todo>); |
u32 cannot be listed for T on unnamed | each instantiation is presented under the name of its type (draft(Todo.self) in Swift, draft(Todo::class) in Kotlin, draft("Todo") in TypeScript), so a listed type is a value type declared with #[undra::api]: a record, an enum, a newtype or a named instantiation | list the element type and write Vec<T> in the signature, or give the type a name: #[undra::api] pub struct Todos(pub Vec<Todo>); |
E0073 an infinite query that does not meet ADR-043's shape: no item_key or one that names no field of the rows, no or more than one #[undra(cursor)] parameter, a cursor that is not Option<C> or is in the key, a success type that is not Page<T, C>, rows that are not a record#
Raised by macros, schema validation.
an infinite query (ADR-043) that is not a list of records with a cursor: no item_key, or one that names no field of the rows; no or more than one #[undra(cursor)] parameter, a cursor that is not Option<C> or is part of the key; a success type that is not Page<T, C> (with C the cursor's type) or rows that are not a record; item_key, refetch_pages or persist_pages without infinite, persist_pages without persist, #[undra(cursor)] on a query that is not infinite; in the schema an infinite mutation or a returns that is not Vec<T> of a record with the item_key field: the handle shows the pages as one list keyed by a field of its rows, and each page is asked for with the cursor the previous one returned
| What you see | Why | Fix |
|---|---|---|
the infinite query no_cursor has no #[undra(cursor)] parameter | the core asks for each page with the cursor the previous one returned: exactly one parameter carries it, None for the first page | mark one parameter #[undra(cursor)] cursor: Option<String> (or the cursor type your server uses) |
the infinite query two_cursors has 2 #[undra(cursor)] parameters | the core asks for each page with the cursor the previous one returned: exactly one parameter carries it, None for the first page | mark one parameter #[undra(cursor)] cursor: Option<String> (or the cursor type your server uses) |
the cursor cursor of not_an_option is String, not an Option<C> | the cursor is None for the first page and the previous page's next after it | write #[undra(cursor)] cursor: Option<String>, or another value type for the cursor your server uses |
the cursor cursor is in the key of the infinite query in_the_key | every page of one list shares one cache entry, so the cursor, which differs per page, cannot be part of its key | remove the placeholder from key; the key holds the parameters that distinguish lists |
#[undra(cursor)] on cursor, which is not a parameter of an infinite query | the cursor is how an infinite query asks for its next page; an ordinary query has no pages | remove the attribute, or add infinite and item_key = ".." to the query |
item_key = "idd" of the infinite query typo names no field of Post | item_key names the field of the rows that identifies them, and Post has the fields id, title | write the name of one of those fields as item_key |
E0074 the impl block of a generic object that is not for the type with its own type parameters, each exactly once, or a method of a generic object with type parameters of its own (ADR-058; addition)#
Raised by macros.
the impl block of a generic object (ADR-058) that is not for the type with its own type parameters, each exactly once (impl<T> Cache<Vec<T>>, impl<T> Cache<T, Todo>, a parameter applied twice or not at all), or a method of a generic object that has type parameters of its own, with or without a generic(..) list: an instantiation is one class on each platform, and a second level of generics would multiply every one of them
| What you see | Why | Fix |
|---|---|---|
the impl block of the generic object Cache is for Cache<Vec<T>> | a generic object is instantiated by naming its type arguments (pub type TodoCache = Cache<Todo>;), so its block is for the type with its own parameters, each exactly once | write impl<T> Cache<T> and put the type you meant in the methods' types |
the impl block of the generic object Pair is for Pair<A, Todo> | a generic object is instantiated by naming its type arguments (pub type TodoPair = Pair<Todo, Tag>;), so its block is for the type with its own parameters, each exactly once | write impl<A, B> Pair<A, B> and put the type you meant in the methods' types |
the impl block of the generic object Twin is for Twin<A, A> | a generic object is instantiated by naming its type arguments (pub type TodoTwin = Twin<Todo, Tag>;), so its block is for the type with its own parameters, each exactly once | write impl<A, B> Twin<A, B> and put the type you meant in the methods' types |
generic(..) on convert, a method of the generic object Box2 | an instantiation of a generic object is one class on each platform; a type parameter on a method would multiply every instantiation by it | make the parameter a type parameter of the object and name it in the alias, or write the method for a concrete type |
generic parameter U on map, a method of the generic object Box2 | an instantiation of a generic object is one class on each platform; a type parameter on a method would multiply every instantiation by it | make the parameter a type parameter of the object and name it in the alias, or write the method for a concrete type |
The command line#
C0001 no undra.toml from start up to the filesystem root#
Raised by undra.
not inside an Undra project: no undra.toml from the working directory up to the filesystem root
| What you see | Why | Fix |
|---|---|---|
| no undra.toml found in <dir> or any parent directory | this command works on an Undra project, and a project is the directory that holds undra.toml | run it inside a project, point at one with -C <dir>, or create one with undra init <name> |
C0002 a configuration or schema file is unusable#
Raised by undra.
undra.toml or a schema file cannot be read or has a value the CLI cannot use
| What you see | Why | Fix |
|---|---|---|
<dir>/undra.toml: line 2: name in [project] is an integer but must be a string | the file drives the build, so a value the CLI cannot understand would make it guess | write it as a string, for example name = "text" |
C0003 a tool is not installed#
Raised by undra.
a tool the command needs is not installed or not on PATH
| What you see | Why | Fix |
|---|---|---|
cargo was not found | reading the core crate needs cargo, and it is not on your PATH | install Rust with rustup: https://rustup.rs (then open a new terminal) run undra doctor to check the rest of the toolchain |
C0004 a build tool exited with a failure#
Raised by undra.
a build tool ran and failed; its own output follows the diagnostic
| What you see | Why | Fix |
|---|---|---|
cargo metadata failed while reading the core crate (exit status: 101) | the tool's own output above says what it objected to; Undra cannot continue without its result | fix the problem the tool reported and run the command again; undra doctor checks the toolchain |
C0005 the core crate is missing, or is not an Undra core#
Raised by undra.
the core crate is missing, or is not an Undra core
| What you see | Why | Fix |
|---|---|---|
the core crate c0005-core does not depend on Undra | without the undra crate there are no #[undra::api] items to describe, and the schema would be empty | add undra = "0.1" to the core's [dependencies] (or a path to your Undra checkout) |
C0006 the schema could not be extracted from the built core#
Raised by undra.
the schema could not be extracted from the built core
The command prints this diagnostic with the details of the failure that caused it.
C0007 the schema cannot be turned into bindings (bindgen diagnostics)#
Raised by undra.
the schema cannot be turned into bindings (the E0001, E0005, E0006, E0010, E0011, E0031, E0050, E0051, E0052 and E0072 diagnostics of schema validation follow)
| What you see | Why | Fix |
|---|---|---|
| the schema cannot be turned into bindings (1 problem) | the public surface of the core has to be expressible in Swift, Kotlin and TypeScript, and these items are not | change the items named below in the core (each message says what to do), then run undra bindgen again |
C0008 the command would overwrite something it must not#
Raised by undra.
undra init or undra adopt would write into a directory that already has files in it
| What you see | Why | Fix |
|---|---|---|
| <dir>/taken already exists and is not empty | undra init creates a new project and will not write into a directory that has files in it | choose another name, or another parent with --dir; to add Undra to an existing app use undra adopt <dir>/taken |
C0009 an argument is unusable#
Raised by undra.
an argument has a value the command cannot use
| What you see | Why | Fix |
|---|---|---|
HEAD has no schema.json | --against compares the schema file committed at the ref with the one in the working tree, so the ref has to have it | commit the schema file there (undra schema export -o schema.json), name another file, or compare two files (undra schema diff old.json new.json) |
my app cannot be a project name: it contains characters other than ASCII letters, digits, - and _ | the name becomes a Cargo package (<name>-core), a Swift module and a Kotlin package, which are stricter than file names | choose a name like todo-app or acme_notes you can still call the folder anything: undra init my-app --dir <parent> |
C0010 an I/O operation failed#
Raised by undra.
a file or directory operation failed
| What you see | Why | Fix |
|---|---|---|
| could not create <dir>/afile/demo: Not a directory (os error 20) | the command needs to read or write this path and the operating system refused | check that the path exists and that you may access it, then run the command again |
C0011 the Rust toolchain lacks a compilation target#
Raised by undra.
the Rust toolchain lacks a compilation target the build needs
| What you see | Why | Fix |
|---|---|---|
the Rust target wasm32-unknown-unknown is not installed | building for this platform needs the standard library compiled for it, and rustup has not installed it | rustup target add wasm32-unknown-unknown |
C0012 the platform is not available on this machine#
Raised by undra.
the platform is not available on this machine
The command prints this diagnostic with the details of the failure that caused it.
C0013 the dev server failed to start or crashed#
Raised by undra.
the dev server failed to start or crashed
The command prints this diagnostic with the details of the failure that caused it.
C0014 the project's Undra does not match: the core's comes from elsewhere, or it is newer#
Raised by undra.
the core and the project disagree about where Undra comes from, or the project is on a newer Undra than this undra (undra upgrade moves a project forward only)
| What you see | Why | Fix |
|---|---|---|
| core/Cargo.toml pins Undra at tag v999.0.0, newer than this undra (<version>) | undra upgrade moves a project forward only, and a CLI older than the project's runtimes would generate bindings they do not match (ahead is <dir>/ahead) | update this undra first (curl -fsSL https://shreypdev.github.io/undra/install.sh | sh, or cargo install --locked --force --git https://github.com/shreypdev/undra undra-cli if you installed it with cargo) and run undra upgrade again |
undra.toml says Undra is at /somewhere/else, but the core's undra dependency is at <repo> | the library Undra ships is built from the same Undra as the core, and the platform runtimes come from [undra] path; if they differ, the core and the apps would speak different wire formats | make them agree: set path of the core's undra dependency and [undra] path in undra.toml to the same checkout (or remove [undra] path to use released runtimes) |
Runtime messages#
The JavaScript runtime (@undra/runtime) throws and logs these. Its production build (what vite build, webpack in production mode and anything else that asks for neither the development nor the react-native condition resolve) says a code, the values and a link instead of a sentence, so a page does not carry the prose of an error whose class, kind and fields it already has: T0017: callSync, remote; see https://shreypdev.github.io/undra/docs/errors.html#T0017. Its development build (Vite's dev server, Vitest, React Native) says the sentence. Both throw the same classes with the same kind and fields; only message differs, so nothing a program can branch on changes. Text the runtime hands on as data, the field of a port's typed error (which the core receives) and a WebSocket close frame's reason (which the peer receives), is not a message: it is the same sentence in both builds. Codes are never reused.
The T codes (166)#
The sentence is what the development build says; {0}, {1}, ... are the values the production message lists, in that order.
| Code | The development build says | Raised by |
|---|---|---|
T0001 | unknown {0} variant: {1} | adapters/codecs.ts: TypeError; adapters/events.ts: RangeError |
T0002 | unknown WsMessage variant: {0} | adapters/codecs.ts: TypeError |
T0003 | unknown WsError variant: {0} | adapters/codecs.ts: TypeError |
T0004 | unknown SseError variant: {0} | adapters/codecs.ts: TypeError |
T0005 | unknown DbValue variant: {0} | adapters/codecs.ts: TypeError |
T0006 | unknown DbError variant: {0} | adapters/codecs.ts: TypeError |
T0018 | namespace {0} is not [a-z][a-z0-9_]{0,31} | adapters/names.ts: UndraError("options") |
T0019 | Rng.fill: {0} bytes requested, the limit is {1} | adapters/ports.ts: RangeError |
T0020 | {0}: {1} ({2}) | adapters/ports.ts: log |
T0024 | WebCrypto is required (crypto.getRandomValues) | adapters/system.ts: VariableDeclaration |
T0025 | a typed error that does not decode ({0} bytes) | call-error.ts: UndraCallError.Malformed |
T0026 | a stream without an error type ended with a typed error item ({0} bytes) | call-error.ts: UndraCallError.Malformed |
T0027 | an unexpected failure: {0} | call-error.ts: UndraCallError.Malformed |
T0028 | the Undra core cancelled the call (a restore replaced its object, or the core shut down) | call-error.ts: super("cancelledByCore") |
T0029 | the Undra core panicked: {0} | call-error.ts: super("panicked") |
T0030 | the Undra core refused the call: {0} | call-error.ts: super("refused") |
T0031 | the Undra core is unavailable: {0} | call-error.ts: super("unavailable") |
T0032 | the Undra core sent a reply the bindings cannot read: {0} | call-error.ts: BinaryExpression |
T0033 | {0} failed: {1} | call-error.ts: super("unhandled"); worker.ts: log |
T0034 | the reply does not decode: {0} | call-error.ts: UndraCallError.Malformed |
T0035 | a port implementation's typed failure reached a call | call-error.ts: UndraCallError.Malformed |
T0036 | the core answered with a typed error, but this method has none ({0} bytes) | call-error.ts: UndraCallError.Malformed |
T0037 | the core opened a stream where a single reply was expected | call-error.ts: UndraCallError.Malformed |
T0038 | the core answered with status {0} as a failure | call-error.ts: UndraCallError.Malformed |
T0039 | u64 out of range: {0} | call-head.ts: RangeError |
T0040 | a bare CallTarget must be FreeFunction; pass { target, handle } for a method | call-head.ts: TypeError |
T0041 | u32 out of range: {0} | call-head.ts: RangeError |
T0042 | the callback's target was garbage-collected | callbacks.ts: UndraError("state") |
T0043 | callback instance {0} was released more often than it was lent | callbacks.ts: UndraError("state") |
T0044 | the core is not loaded: load it at app startup (the bindings' Undra<Namespace>.load(...), or UndraCore.load(...)), before creating any Undra object, or pass a core explicitly | core.ts: VariableDeclaration |
T0045 | The operation was aborted | core.ts: Error |
T0046 | a core was used while it is not loaded (before its load(...) succeeded, or after it was closed); calls on it reject with UndraCallError.Unavailable. Load the core at app startup, before creating any Undra object. | core.ts: log |
T0047 | mode 'wasm-main' needs the wasm option | core.ts: UndraError("options") |
T0048 | import failed: {0} | core.ts: log |
T0049 | unknown mode '{0}' | core.ts: UndraError("options") |
T0050 | the core is closed | core.ts: PropertyDeclaration; core.ts: UndraTransportError("closed"); transport/wasm-main.ts: UndraTransportError("closed"); ... |
T0051 | the core returned a truncated reply | core.ts: UndraTransportError("protocol") |
T0052 | the core returned the null handle for a constructor | core.ts: UndraTransportError("protocol") |
T0053 | {0} (the connection to the core is down: see UndraCore.connection) | core.ts: log |
T0054 | the onError handler threw while handling "{0}": {1} | core.ts: log |
T0055 | the core was closed | core.ts: UndraTransportError("closed") |
T0056 | the core sent a truncated reply | core.ts: UndraTransportError("protocol") |
T0057 | the core sent reply status {0} | core.ts: UndraTransportError("protocol"); stream-support.ts: UndraTransportError("protocol") |
T0058 | this method is a stream; call it with UndraCore.stream | core.ts: UndraError("state") |
T0084 | the dev server no longer has this core's objects (it was restarted, or the session expired); load a new core | errors-rare.ts: Parameter |
T0085 | the Undra core rejected the snapshot (code {0}); a rejected restore leaves the core unchanged | errors-rare.ts: super("restore") |
T0086 | the call failed with a typed error | errors.ts: ReturnStatement |
T0087 | the core panicked | errors.ts: ConditionalExpression |
T0088 | the core panicked: {0} | errors.ts: ConditionalExpression |
T0089 | the call was cancelled | errors.ts: ReturnStatement |
T0090 | the core rejected the request | errors.ts: ConditionalExpression |
T0091 | the core rejected the request: {0} | errors.ts: ConditionalExpression |
T0092 | unexpected reply status {0} | errors.ts: ReturnStatement |
T0093 | {0} is not available in mode '{1}' | errors.ts: super("mode") |
T0094 | schema mismatch: the bindings expect {0} but the core reports {1}; regenerate the bindings or rebuild the core | errors.ts: super("schemaMismatch") |
T0095 | typed port failure | errors.ts: super("port") |
T0096 | the core sent the null handle where an object was expected | identity.ts: UndraTransportError("protocol") |
T0097 | the core sent option tag {0} | identity.ts: UndraTransportError("protocol") |
T0098 | {0} belongs to another core: pass an object of the core the call goes to | identity.ts: UndraCallError.Refused |
T0099 | {0} must be an integer between 1 and {1}, not {2} | lazy.ts: RangeError |
T0100 | a lazy list was invalidated before its value (and so its page server) reached the host | lazy.ts: UndraTransportError("protocol") |
T0101 | the core sent {0} rows for page {1} of a list of {2}, which holds {3} | lazy.ts: UndraTransportError("protocol") |
T0102 | the core sent a list length of {0} at version {1}, which it told us had {2} | lazy.ts: UndraTransportError("protocol") |
T0103 | the core keeps answering page {0} at version {1}, older than the list's {2} | lazy.ts: UndraTransportError("protocol") |
T0104 | no change-set arrived for signal {0} of handle {1} within {2} ms; is the handle a live store? | mirror-waiters.ts: UndraError("observe") |
T0105 | handle {0} is already registered with the mirror | mirror.ts: UndraError("state") |
T0106 | the mirror applied {0} rounds of change-sets in one flush: a signal subscriber keeps causing changes to a store it observes | mirror.ts: UndraError("state") |
T0107 | a keyed patch for signal {0} of handle {1} has no operation count; the signal is re-observed | mirror.ts: UndraError("state") |
T0108 | this mirror has no observe waiters: a core installs them for a transport that answers later; for any other mirror call mirrorWaiters(mirror) (from @undra/runtime) once, before whenObserved | mirror.ts: UndraError("state") |
T0109 | {0} needs Node; this is not Node | node-builtin.ts: ConditionalExpression |
T0110 | {0} needs Node 20.16 or 22.3 or later (process.getBuiltinModule); this is Node {1} | node-builtin.ts: ConditionalExpression |
T0111 | this Node has no {0} | node-builtin.ts: Error |
T0112 | the runtime's {0} could not be loaded: {1} | on-demand.ts: UndraTransportError("closed") |
T0113 | {0} method 0x{1} | port-dispatch.ts: ReturnStatement |
T0122 | the events of this stream were already taken | realtime/fetch-sse.ts: TypeError |
T0128 | the messages of this connection were already taken | realtime/inbox.ts: TypeError |
T0129 | a next() is already pending | realtime/inbox.ts: TypeError |
T0130 | ByteQueue.at past the end | realtime/node-websocket.ts: RangeError |
T0156 | the wasm core trapped and was restarted from its last snapshot; this call may or may not have run before the trap, and it is not retried ({0}) | recovery.ts: UndraTransportError("restarted") |
T0157 | the wasm core trapped ({0}) and was restarted from no snapshot | recovery.ts: BinaryExpression |
T0158 | a snapshot of {0} bytes was not kept for crash recovery: it is larger than maxSnapshotBytes ({1}); the previous one stays (said once) | recovery.ts: log |
T0159 | a snapshot for crash recovery failed: {0} | recovery.ts: log |
T0160 | the core refused its last snapshot (code {0}) after the restart; it runs without its stores | recovery.ts: log |
T0161 | this crashRecovery() already belongs to a core: make one per core | recovery.ts: UndraTransportError("unsupported") |
T0162 | the wasm core is restarting after a trap | recovery.ts: UndraTransportError("restarted") |
T0163 | the wasm core could not be restarted: {0} | recovery.ts: this.#log |
T0164 | {0}: {1} call(s) in flight failed, {2} object(s) went stale | recovery.ts: this.#log |
T0165 | the onCoreRestarted handler threw: {0} | recovery.ts: this.#log |
T0168 | the core answered a stream call with a plain result | stream-support.ts: UndraTransportError("protocol") |
T0169 | the core sent a truncated stream item | stream-support.ts: UndraTransportError("protocol") |
T0170 | the core sent a malformed stream failure: {0} | stream-support.ts: UndraTransportError("protocol") |
T0171 | the core sent stream flag {0} | stream-support.ts: UndraTransportError("protocol") |
T0172 | could not grant stream credit | stream.ts: UndraError("state") |
T0173 | adapters.{0} are ignored in wasm-worker mode: set them in LoadOptions.worker.ports | transport/framed.ts: log |
T0174 | the connection to the core was lost ({0}); reconnecting | transport/framed.ts: UndraTransportError("closed") |
T0175 | this platform has no WebSocket; pass webSocket to use another implementation | transport/remote.ts: UndraTransportError("unsupported") |
T0176 | could not connect to {0}: {1} | transport/remote.ts: UndraTransportError("handshake") |
T0177 | could not send Hello: {0} | transport/remote.ts: UndraTransportError("handshake") |
T0178 | the core sent a text message; Undra speaks binary envelopes | transport/remote.ts: UndraTransportError("protocol") |
T0179 | the connection to {0} closed (code {1}{2}) | transport/remote.ts: VariableDeclaration |
T0180 | {0} before the core answered Hello | transport/remote.ts: UndraTransportError("handshake") |
T0181 | could not connect to {0} | transport/remote.ts: UndraTransportError("handshake") |
T0182 | {0} did not complete the Hello exchange within {1} ms | transport/remote.ts: UndraTransportError("timeout") |
T0183 | the connection is closed | transport/remote.ts: ConditionalExpression |
T0184 | the core is not connected | transport/remote.ts: ConditionalExpression |
T0185 | the core is not connected: reconnecting | transport/remote.ts: ConditionalExpression |
T0186 | expected Hello from the core, got {0} | transport/remote.ts: UndraTransportError("handshake") |
T0187 | bad Hello from the core: {0} | transport/remote.ts: UndraTransportError("handshake") |
T0188 | bad message from the core: {0} | transport/remote.ts: UndraTransportError("protocol") |
T0189 | mode 'remote' needs the url option | transport/remote.ts: UndraError("options") |
T0190 | cannot send a {0} message to a wasm core | transport/wasm-main-transport.ts: UndraTransportError("protocol") |
T0191 | the core refused the call (undra_call returned {0}) | transport/wasm-main.ts: encodeValue |
T0192 | undra_alloc({0}) returned 0 instead of trapping | transport/wasm-main.ts: Error |
T0193 | WebAssembly is not available on this platform | transport/wasm-main.ts: UndraTransportError("unsupported") |
T0194 | GET {0} answered {1} | transport/wasm-main.ts: Error |
T0195 | could not instantiate the wasm core: {0} | transport/wasm-main.ts: UndraTransportError("handshake") |
T0196 | the module is not an Undra core: it does not export {0} | transport/wasm-main.ts: UndraTransportError("handshake") |
T0197 | the core speaks wasm ABI {0}, this runtime speaks {1} | transport/wasm-main.ts: UndraTransportError("handshake") |
T0198 | undra_init failed with code {0} | transport/wasm-main.ts: UndraTransportError("handshake") |
T0199 | the core handed out [{0}, {1}) beyond its {2} bytes of memory | transport/wasm-main.ts: RangeError |
T0200 | the core returned a null UndraBuf | transport/wasm-main.ts: UndraTransportError("protocol") |
T0201 | the core is not started | transport/wasm-main.ts: ConditionalExpression; transport/wasm-worker.ts: ConditionalExpression |
T0202 | the wasm core trapped: {0} | transport/wasm-main.ts: UndraTransportError("trap") |
T0203 | the core does not export undra_snapshot | transport/wasm-main.ts: UndraTransportError("unsupported") |
T0204 | the core does not export undra_restore | transport/wasm-main.ts: UndraTransportError("unsupported") |
T0205 | the worker gave an incomplete answer | transport/wasm-worker.ts: UndraTransportError("protocol") |
T0206 | worker.ports needs this @undra/runtime's worker script (protocol 3) | transport/wasm-worker.ts: UndraTransportError("unsupported") |
T0207 | the worker sent an envelopes message without a list of envelopes | transport/wasm-worker.ts: UndraTransportError("protocol") |
T0208 | worker error: {0} | transport/wasm-worker.ts: UndraTransportError |
T0209 | the worker sent a message that could not be deserialised | transport/wasm-worker.ts: UndraTransportError("protocol") |
T0210 | the worker did not start within {0} ms | transport/wasm-worker.ts: UndraTransportError("timeout") |
T0211 | could not reach the worker: {0} | transport/wasm-worker.ts: UndraTransportError("handshake"); transport/wasm-worker.ts: UndraTransportError("closed") |
T0212 | the worker script cannot {0}: rebuild it with this @undra/runtime | transport/wasm-worker.ts: UndraTransportError("unsupported") |
T0213 | this platform has no Worker; pass worker to run the core on one | transport/wasm-worker.ts: UndraTransportError("unsupported") |
T0214 | bad message from the worker: {0} | transport/wasm-worker.ts: UndraTransportError("protocol") |
T0215 | {0} is synchronous: in wasm-worker mode, register it in LoadOptions.worker.ports | transport/wasm-worker.ts: ReturnStatement |
T0216 | mode 'wasm-worker' needs the wasm option | transport/wasm-worker.ts: UndraError("options") |
T0217 | a decimal's scale is an integer from 0 to {0}, got {1} | wire/decimal.ts: RangeError |
T0218 | a decimal's mantissa must fit a signed 128-bit integer | wire/decimal.ts: RangeError |
T0219 | not a decimal: {0} | wire/decimal.ts: SyntaxError |
T0220 | unknown envelope kind: {0} | wire/envelope.ts: RangeError |
T0221 | envelope seq out of range: {0} | wire/envelope.ts: RangeError |
T0222 | envelope schema hash out of range: {0} | wire/envelope.ts: RangeError |
T0223 | raw length out of range: {0} | wire/reader.ts: RangeError |
T0224 | handle index out of range: {0} | wire/types.ts: RangeError |
T0225 | handle generation out of range: {0} | wire/types.ts: RangeError |
T0226 | handle out of range: {0} | wire/types.ts: RangeError |
T0227 | cannot convert an invalid Date to a Timestamp | wire/types.ts: RangeError |
T0228 | timestamp {0} is outside the range of a Date | wire/types.ts: RangeError |
T0229 | duration must be finite: {0} | wire/types.ts: RangeError |
T0230 | duration exceeds i64 nanoseconds: {0} ms | wire/types.ts: RangeError |
T0231 | invalid UUID "{0}": expected 8-4-4-4-12 hex digits (36 characters) and room for 16 bytes at offset {1} of {2} | wire/types.ts: RangeError |
T0232 | need 16 bytes for a UUID at offset {0} of {1} | wire/types.ts: RangeError |
T0233 | {0} out of range: {1} | wire/writer.ts: RangeError |
T0234 | the worker could not import the ports module {0}: {1} | worker.ts: UndraTransportError("handshake") |
T0235 | the default export of the ports module {0} must map port ids to implementations | worker.ts: UndraTransportError("handshake") |
T0236 | the ports module {0} maps {1} to something that is not a port implementation ({ sync, methods }, as registerPort takes) | worker.ts: UndraTransportError("handshake") |
T0237 | the worker's transport cannot snapshot or restore | worker.ts: UndraTransportError("unsupported") |
T0238 | {0} port 0x{1} could not release what it held: {2} | worker.ts: log |
T0239 | could not deliver a port reply: {0} | worker.ts: log |
T0240 | internal error: {0} | worker.ts: log |
T0241 | dropped a malformed envelope from the host: {0} | worker.ts: log |
T0242 | the worker was not started with recovery | worker.ts: UndraTransportError("unsupported") |
T0243 | the wasm core trapped ({0}) and was restarted from a snapshot {1} ms old | recovery.ts: UndraCoreRestarted |
T0244 | keyed patch operation #{0} ({1}) index {2} is out of bounds for a list of length {3} | wire/errors.ts: PatchError |
T0246 | the transport passes {0} as calls but not {1}: a transport has all seven control methods (observe, release, cancel, streamCredit, event, timerFired, portReply) or none, and send frames them | transport/framed.ts: UndraError("options") |
Wire failures#
A WireError says its code and fields in a production build (wire: code=unexpected_eof at=12 needed=3; see link); the development build says the sentence below, with the values in braces.
| Code | The development build says |
|---|---|
unexpected_eof | unexpected end of input at offset {at}: needed {needed} more byte(s) |
invalid_utf8 | invalid UTF-8 in string at offset {at} |
invalid_tag | invalid {ty} tag {tag} at offset {at} |
length_too_large | length {len} at offset {at} exceeds the available input |
trailing_bytes | {count} trailing byte(s) after the end of the message |
bad_magic | bad magic: envelope does not start with 554e4452 |
unsupported_version | unsupported wire version {version} |
schema_mismatch | schema mismatch: expected 0x{expected}, got 0x{got} |
duplicate_key | duplicate map key at offset {at} |
negative_duration | negative duration ({nanos} ns) |
unsafe_integer | integer {value} at offset {at} is outside the JS safe integer range |
Generated by site/scripts/build-errors.mjs from docs/SPEC.md section 12, the compile-fail tests of the macros crate and the message goldens of the other crates. To change a message, change the code that raises it and regenerate its golden; to change the catalogue, change the specification.
Generated from the specification and the macro tests: edit those, not this page.