# Error codes

> Every code a production build of Gyral prints, such as G0010: what the message says, what it means and how to fix it.

Source: https://gyral.dev/errors/

Development builds of `@gyral/core` print each diagnostic in full, ending with its code and a link to this page: `… (G0010: https://gyral.dev/errors/#G0010)`. Production builds print a short line instead, so the message texts stay out of your bundle: `Gyral`, the code, the message’s arguments in order, and the link.

```text
Gyral G0010 my-cart Add https://gyral.dev/errors/#G0010
```

Read that one as: `<my-cart>` has no update for the message `Add`. Find the code below; its message shows where each argument goes. For the full sentence, reproduce the problem in development (the dev server, tests, or a build with `--mode development`). A hydration mismatch keeps its own sentence in production and ends with its code and link.

The codes and messages are read from `@gyral/core` 0.3.9, the version this site is built with; codes are never reused.

## Components

### G0001

```text
<{tag}> is a browser element (render it on the server with @gyral/ssr).
```

Arguments: `tag`.

Outside the browser, `define()` only records your component for the server renderer, so there is no element class to construct: `new MyElement()` on the server throws this.

**Fix:** Render the component on the server through `@gyral/ssr` (`renderPage`, `renderToString`), instead of constructing it.

### G0010

```text
<{tag}> has no update for message "{message}".
```

Arguments: `tag`, `message`.

A component received a message whose `_tag` has no reducer in its `update`, so the message was dropped. It is usually a typo, or a reducer you forgot.

**Fix:** Add a reducer for the message to the component’s `update`, or stop sending it.

### G0011

```text
<{tag}> has no intent parser for data-intent="{intent}".
```

Arguments: `tag`, `intent`.

An event reached an element whose `data-intent` names an intent the component has no parser for, so the user’s action was ignored.

**Fix:** Add a parser with that name to the spec’s `intent`, or correct the name in the view (`data-intent=${i.Name}` catches typos at compile time).

### G0012

```text
<{tag}> intent parser for "{intent}" failed
```

Arguments: `tag`, `intent`.

An asynchronous intent parser rejected. The error is logged with this message, and the event produced no message.

**Fix:** Handle failures inside the parser (return a message that describes the failure, or `undefined`), or move the fallible work into a command with `onFailure`.

### G0013

```text
<{tag}> focus("{selector}") matched no focusable element.
```

Arguments: `tag`, `selector`.

A `focus(selector)` command found no element to focus in the component’s root after the render, so focus stayed where it was. Keyboard and screen reader users notice.

**Fix:** Make the selector match an element inside the component (its shadow root, or its children for `shadow: false`). Give targets that aren’t focusable, such as headings, `tabindex="-1"`.

### G0014

```text
<{tag}> is on the page, but no custom element named "{tag}" is defined {seconds} s after it loaded, so it renders nothing. If it is one of your components, import the module that calls define()('{tag}', …) from the entry; for a third-party element, load its package. Ignore this for an element defined later on purpose.
```

Arguments: `tag`, `seconds`.

Development builds look for custom-element tags on the page that nothing has defined, 3 seconds after load and again after each later `define()`. Such an element renders nothing: usually the entry never imports the module that defines it.

**Fix:** Import the component’s module from the entry (or from a module the entry imports). For a third-party element, load its package; ignore the warning for an element you define later on purpose.

### G0015

```text
Two copies of @gyral/core run in this page: {first} from {firstUrl}, and {second} from {secondUrl}. A value one copy makes, such as a stylesheet from css or a store, does not work in the other. Install one copy: pin @gyral/core to one version with your package manager's overrides (gyral() warns when it is installed more than once).
```

Arguments: `first`, `firstUrl`, `second`, `secondUrl`.

Development only: two copies of `@gyral/core` run in the page. A value one copy makes, such as a stylesheet from `css` or a store, doesn’t work in the other, so components fail far from the cause (`styles.flatMap is not a function`). `gyral()` also warns at startup, in dev and builds, when the package is installed more than once, naming each copy’s version, folder and the packages that use it.

**Fix:** Give every `@gyral/*` package the same version: they take `@gyral/core` as a peer, so they share the app’s copy. For a library that pins another core, pin `@gyral/core` to one version with your package manager’s overrides (pnpm or npm `overrides`, Yarn `resolutions`) and reinstall. A library lists `@gyral/core` as a peer dependency ([Publishing a component library](https://gyral.dev/docs/packages/#publishing-a-component-library)).

### G0016

```text
{package} {version} needs @gyral/core {version}, but this app has @gyral/core {core}. Gyral's packages are released together: install the same version of every @gyral package.
```

Arguments: `package`, `version`, `core`.

A Gyral package (`@gyral/http`, `router`, `time`, `ssr`, `testing` or `devtools`) loaded with a `@gyral/core` of another release. Each one uses core’s internals, which change between releases, so it checks core’s version when it loads. They take `@gyral/core` as a peer at their exact version, so the package manager normally reports the mismatch when it installs: pnpm lists the unmet peer, npm stops with `ERESOLVE`. Development throws, naming both versions; production logs this warning and carries on.

**Fix:** Install the same version of every `@gyral/*` package the app uses, and check that the lockfile resolves one version of each ([One version of every package](https://gyral.dev/docs/packages/#one-version-of-every-package)).

### G0017

```text
<{tag}> rendered differently with the same state, props and stores, so its view reads something else, such as Date.now(), a module variable or the DOM, or builds a value anew each render that is compared by reference (a Date, a Set, a class instance). It differs {where}. A component renders only when one of them changes (0.3.8): move what the view reads into state, a prop or a store.
```

Arguments: `tag`, `where`.

Development only: a component renders only when its state, a declared prop or a declared store’s value changes, and this one rendered differently when Gyral rendered a skipped view again to check it. So its view reads something else, such as `Date.now()`, `Math.random()`, a module variable or the DOM, and on the page it shows a stale value until one of its inputs changes. The check compares what the view renders, plain objects and arrays by value, so values a view builds anew each render match when they are equal; a `Date`, a `Set` or a class instance built in the view compares by reference, so it differs every time. `where` says where the view differs: `in its template`, or in the innermost `each(…, Row)` or `keyed(…)` that does, named by its row function. When that list’s `pick` returned a new object for the same item, the message says so. Development checks up to 50 skipped views per render pass (a different 50 each pass when more are skipped, so every component is checked within a few passes) and warns once per component.

**Fix:** Move what the view reads into state (the time from an `every` subscription, a random value from a command, a `Date` built from a timestamp), a prop or a store, so that a change to it renders the component ([Pure means repeatable](https://gyral.dev/docs/views/#pure-means-repeatable)). When the message names a list’s `pick`, pick only the fields the row reads, or pass `each(items, key, row, { pick, equals })`.

### G0018

```text
The parser of intent "{intent}" is on("{expected}"), but a "{actual}" event reached it. Bind the intent to that event (data-intent-{expected}=${…}), or give it a parser of its own.
```

Arguments: `intent`, `expected`, `actual`.

The intent’s parser is `on(event, …)`, written for one event type, but another event reached it: the template binds the intent to a different event, through the element’s own trigger, `data-intent-on` or another `data-intent-<event>` attribute. Development throws; production declines the event, as a parser that returns `undefined` does. The `gyral/intent-event` ESLint rule reports the same binding in the editor.

**Fix:** Bind the intent to the parser’s event, `data-intent-keydown=${i.Move}` for `on("keydown", …)`, or give the other event an intent and a parser of its own ([Parsers typed by their event](https://gyral.dev/docs/intent/#parsers-typed-by-their-event)).

## Props

### G0020

```text
<{tag}> prop "{prop}" has an asynchronous schema; it must be synchronous.
```

Arguments: `tag`, `prop`.

A prop’s Standard Schema returned a promise. Props are validated synchronously, while the element updates and renders, so they can’t wait for it.

**Fix:** Use a synchronous schema or a type guard for the prop, and do asynchronous checks in a command.

### G0021

```text
<{tag}> prop "{prop}" got an invalid value from {source}, so it is treated as missing: {issues}
```

Arguments: `tag`, `prop`, `source`, `issues`.

A prop value failed its type or its schema, so it is treated as missing and its `default` applies. Attributes are checked in every build; property sets and hydration seeds in development only.

**Fix:** Pass a value that matches the prop’s declaration (a numeric string for `prop.number`, valid JSON for `prop.json`), or loosen the schema.

### G0022

```text
<{tag}> is missing required prop(s): {props}.
```

Arguments: `tag`, `props`.

A component rendered for the first time while props declared `required` were still missing. The parent probably forgot an attribute or a property.

**Fix:** Set the prop on the element (an attribute, or `.prop=${…}`) before it renders, or give it a `default` instead of `required`.

### G0023

```text
<{tag}> declares prop(s) named like a member every element already has: {props}. The prop would replace it: a prop named "hidden" hides the element, one named "state" hides the component's model. Rename the property. The name of one of Gyral's members (state, send, drivers, stores) can stay the attribute: badge: prop.string({ attribute: "state" }).
```

Arguments: `tag`, `props`.

A component declares props named like a member every element already has: a built-in property (`hidden`, `title`, `id`), or one of Gyral’s (`state`, `send`, `drivers`, `stores`, `initialMessages`, the custom-element callbacks). The prop would replace the member: a prop named `hidden` hides the element, one named `state` hides the component’s model. TypeScript rejects these names and development throws; production warns about built-in names.

**Fix:** Rename the property. One of Gyral’s names can stay the public attribute: `badge: prop.string({ attribute: "state" })`.

### G0024

```text
<{tag}> has a "{attribute}" attribute, which no prop reads: HTML lowercases attribute names, and prop {prop} reads "{expected}". Write {expected}="…", or set the property (el.{prop} = …).
```

Arguments: `tag`, `attribute`, `prop`, `expected`.

Development only: the element carries an attribute HTML lowercased from a camelCase prop’s name, such as `playerbase` for `playerBase`, written in the page’s HTML or set by a host framework. The prop reads its kebab-case attribute, `player-base`, so the value never reached it.

**Fix:** Write the prop’s attribute (`player-base="…"`), or set the property in code. In templates, the build and ESLint report the same mistake ([template rules](https://gyral.dev/docs/views/#checked-before-it-runs)).

## Scheduling

### G0030

```text
gyral: a deferred callback failed
```

Arguments: none.

A callback Gyral deferred to a microtask threw: delivering a child component’s output to its parent. The parent may not have received the output.

**Fix:** Look at the error logged with this message, and make sure the parent’s `child()` mapper and any `gyral-output` listener don’t throw.

### G0031

```text
<{tag}> view failed; it shows its error view, or its previous DOM stays.
```

Arguments: `tag`.

A component’s `view` threw during a render. Gyral reports a `GyralError` (phase `view`) through its error channel and keeps rendering the other components. The component renders its `error` view if its spec has one; otherwise its DOM shows its previous state.

**Fix:** Fix the exception in the view, using the `cause` of the reported error. It is often a field read on state that has a different shape than the view expects. Give the spec an `error(failure, state)` view so users see a fallback ([Error handling](https://gyral.dev/docs/error-handling/)).

### G0032

```text
gyral: post-render work failed
```

Arguments: none.

Work that runs after a render failed: a focus command, custom states from `states`, the `Hydrated` message, or the commands `init` returned for a resumed component.

**Fix:** Fix the exception logged with this message, typically in the spec’s `states` function or the `Hydrated` reducer.

### G0033

```text
gyral: rendering did not settle in one flush (a cycle between {tags}). Components are probably feeding each other props or messages; break the cycle with a condition in update.
```

Arguments: `tags`.

Rendering didn’t settle in one flush: the named components kept re-rendering each other. Components are probably feeding each other props or messages in a cycle. Development throws; production logs it and drops the rest of the work so the page doesn’t freeze.

**Fix:** Break the cycle with a condition in `update`, for example by sending a message or changing state only when the value actually differs.

### G0034

```text
settled(): the page did not settle after {rounds} flushes or busy turns. A stream is emitting without pause, or components (or drivers) are feeding each other messages in a cycle.
```

Arguments: `rounds`.

`settled()` rejected because messages kept arriving: more than the given number of flushes or busy turns went by without a quiet moment. Something is sending messages in a cycle, or a stream emits on every turn.

**Fix:** Find the cycle and break it with a condition in `update`, or substitute the chatty driver in the test.

## Commands

### G0040

```text
{owner}: the onSuccess or onFailure mapper for driver "{driver}" threw; no message was sent.
```

Arguments: `owner`, `driver`.

A command’s `onSuccess` or `onFailure` mapper threw while turning a driver’s result into a message, so the result never reached `update`. It is reported as a `GyralError` (phase `command`), and the component’s `Errored` reducer, if any, receives it.

**Fix:** Make the mapper total: return a message, or `undefined`, for every input.

### G0041

```text
{owner}: driver "{driver}" failed and the command has no onFailure.
```

Arguments: `owner`, `driver`.

A driver failed, after any `retry()` policy, and the command has no `onFailure`. This is an error, not a warning: it is reported as a `GyralError` (phase `command`) and reaches the component’s `Errored` reducer, if any. Without one, the component can’t react: a spinner may spin forever.

**Fix:** Give the command an `onFailure` that turns the error into a message, and handle that message in `update`. Expected failures (the network, a 5xx, a refusal) should always be messages.

### G0042

```text
gyral: subscription "{name}" failed to unsubscribe
```

Arguments: `name`.

The function (or `unsubscribe()`) a `subscription()` returned threw when Gyral released the source, so the source may still be sending values or holding listeners.

**Fix:** Make the stop function that `subscribe` returns safe to call once, and return a function or an object with `unsubscribe()`.

### G0043

```text
{owner}: no driver provides "{driver}". It is a driver token: provide its implementation with provideDrivers(root, [token.provide(run)]) or el.drivers. A page provides it before its components' first render: before importing them, or later in the same task (no await in between).
```

Arguments: `owner`, `driver`.

The command’s driver is a token: `defineDriver<I, O, E>(name)` without an implementation of its own. Nothing above the component provides that name, so the command can’t run. It is reported through the error channel (phase `command`); `onFailure` isn’t called, because there was no driver to fail.

**Fix:** Provide the driver where the app starts, `provideDrivers(document.body, [token.provide(run)])`, or on the element with `el.drivers`. A page provides it before its components first render: before importing them, or later in the same task with no `await` in between ([Substituting drivers](https://gyral.dev/docs/effects/#substituting-drivers)). In tests, pass a fake of the token, `fakeDriver(token)`, which takes its name ([Drivers the app provides](https://gyral.dev/docs/effects/#drivers-the-app-provides)).

### G0044

```text
Two drivers named "{name}" in one list of drivers: give each a name of its own, or drop one.
```

Arguments: `name`.

Development only: a list of drivers (for `provideDrivers`, `el.drivers`, `<gyral-drivers>`, `mount({ drivers })` or a store) has two drivers with the same name. A command finds its driver by name, so only one of them could ever run. Development throws; production has no check and uses the first.

**Fix:** Drop one of them, or give each driver a name of its own and build each command from the driver it should use.

### G0045

```text
A driver supplied as "{key}" is named "{name}", so commands of the "{name}" driver never use it. Supply drivers as a list, each under its own name (provideDrivers(root, [driver])), or make the key match.
```

Arguments: `key`, `name`.

Development only: a record of drivers has a key that isn’t the name of the driver under it, such as `{ api: makeHttpDriver() }` for a driver named `http`. A command looks its driver up by the driver’s own name, `http` here, so that entry is never used: the lookup goes on to the next provider and, last, to the command’s own driver (for a token, [G0043](https://gyral.dev/errors/#G0043)). Development warns once per record.

**Fix:** Supply the drivers as a list, each under its own name, `provideDrivers(root, [makeHttpDriver()])`, or make the key the driver’s name ([Substituting drivers](https://gyral.dev/docs/effects/#substituting-drivers)).

## Stores

### G0050

```text
<{tag}> uses store "{store}" without declaring it. Add it to the spec: stores: [{store}], so the component subscribes to its changes.
```

Arguments: `tag`, `store`.

A component read a store with `ctx.read(store)`, or sent to one, without listing it in its spec. A component subscribes only to the stores it declares, so it would miss the store’s changes.

**Fix:** Declare the store in the spec, for example `stores: [cart]`.

### G0051

```text
store "{store}": the server's seed failed its schema, so it starts from init. Issues: {issues}
```

Arguments: `store`, `issues`.

The store state the server seeded into the page failed the store’s `schema`, so the browser discarded it and the store starts from `init`. The page may show different data than the server rendered.

**Fix:** Fix the state the server sends, or align the store’s `schema` with it.

### G0052

```text
unreadable {attribute} seed on {where}
```

Arguments: `attribute`, `where`.

The store seed on the page, or on a `<gyral-stores>` provider, isn’t valid JSON, so every store in it starts from `init`.

**Fix:** Let `@gyral/ssr` write the seed (`renderPage({ stores })`, or the provider’s `.instances`) instead of writing it by hand, and check that nothing rewrites or truncates the HTML on its way.

### G0053

```text
<{tag}> reads store "{store}" during a server render without a store scope. Pass the request's store instances to renderPage({ stores }) or renderToString(value, { stores }).
```

Arguments: `tag`, `store`.

A component read a store during a server render without a store scope. On the server each request needs its own store instances, and without a scope Gyral can’t tell whose state to read.

**Fix:** Render through `@gyral/ssr` and pass the request’s instances: `renderPage({ stores })` or `renderToString(value, { stores })`.

### G0054

```text
store "{store}" sends to "{target}" but is not held by a store scope (a registry, <gyral-stores> or the page default), so the message is dropped.
```

Arguments: `store`, `target`.

A store’s `update` sent a message to another store, but this store instance isn’t held by a store scope, so the message has nowhere to go and is dropped.

**Fix:** Let a scope hold the instance: the page’s default, a `<gyral-stores>` provider (`.instances=${[…]}`), or a store registry in tests.

### G0055

```text
store "{store}" has no update for message "{message}".
```

Arguments: `store`, `message`.

A store received a message whose `_tag` has no reducer in its `update`, so the message was dropped and the change you expected didn’t happen.

**Fix:** Add a reducer for the message to the store’s `update`, or correct the tag being sent.

## Hydration

### G0060

```text
<{tag}> has an unreadable {attribute}
```

Arguments: `tag`, `attribute`.

A server-rendered component’s `data-gyral-seed` isn’t valid JSON, so the browser can’t resume the server’s state: the component starts from `init`, and its first render may not match the server’s HTML.

**Fix:** Don’t edit or write `data-gyral-seed` yourself. Look for whatever changes the server’s HTML on its way: a proxy, an HTML minifier, string templating.

### G0061

```text
gyral: hydration code failed to load; rendering fresh
```

Arguments: none.

The hydration code, which loads lazily with the first server-rendered component, failed to load, so server-rendered components render fresh instead of hydrating. The page works, but redoes the server’s work. It is usually a stale deploy: a cached page that points at a chunk that no longer exists.

**Fix:** Keep the previous build’s assets online for a while after a deploy, or don’t cache HTML that points at removed chunks. The network error is logged with this message.

### G0062

```text
gyral: hydration mismatch in {host} at {path}: expected {expected}, found {found}. The server's HTML differs from the first client render: a view that isn't deterministic (Date.now(), locale), a third party that changed the DOM before scripts ran, or a stale cached page (https://gyral.dev/docs/server-rendering/#mismatches).
```

Arguments: `host`, `path`, `expected`, `found`.

The server’s HTML differs from the first client render, so the component can’t be hydrated in place. Development throws `HydrationMismatch`, naming the template’s file and line; production keeps the sentence (the component, the DOM path, what was expected and found) and renders the component fresh (G0063). Both end the sentence with this code and its link.

**Fix:** Make the view render the same on both sides: no `Date.now()`, random numbers or locale-dependent formatting in `view` (put them in state through a command). Also rule out a browser extension or script that changed the DOM before hydration, and a stale cached page.

### G0063

```text
<{tag}> was rendered fresh after a hydration mismatch.
```

Arguments: `tag`.

Production only: after a hydration mismatch, Gyral cleared this component and rendered it fresh. The warning prints this code with the component’s tag, then the mismatch’s own sentence, which ends with G0062. The rest of the page stays hydrated, but this component flashes and redoes the server’s work.

**Fix:** Fix the mismatch the warning describes; reproducing it in development gives the full message and the template’s location.

## Templates

### G0069

```text
<{element}> ?{binding} does nothing: this build left the dialog and popover code out, because no module the build scanned binds it (a package that does not depend on Gyral is not scanned).
```

Arguments: `element`, `binding`.

Production only: a `?modal` or `?popover-open` binding ran in a build that left the dialog and popover code out, so the dialog didn’t open. The build adds that code when a module it reads binds one, in source or in a package’s compiled templates, and it doesn’t read installed packages that don’t depend on Gyral.

**Fix:** Make the package that ships the template depend on `@gyral/core` (a library lists it as a peer dependency), so the build reads it, or move the template into your own source.

### G0070

```text
gyral: an html template was not compiled: `{start}`. Under the gyral-compiled condition every html`…` must be compiled by the Gyral Vite preset.
```

Arguments: `start`.

A bundle built with the Vite preset leaves out the runtime template preparer, so every `html` template must be precompiled, and this one wasn’t. The build normally fails before this can happen.

**Fix:** Import `html` (and `svg`) from `@gyral/core`, or from a package listed in the compiler’s `sources`, and use it directly as a tag: the compiler can’t follow an alias, a call or a re-export.

### G0071

```text
gyral: template rule 11: a page shell rendered in the browser.
```

Arguments: none.

A page shell, a template with `<!doctype>`, `<html>`, `<head>` or `<body>`, was rendered in the browser. Only the server renders document-level tags. Development reports it as template rule 11, with the full explanation.

**Fix:** Render the page shell on the server with `@gyral/ssr`’s `renderPage`, and render only components in the browser.

### G0072

```text
gyral: this page's Trusted Types policy list does not allow the policy "gyral", so templates are parsed from plain strings, which works only while Trusted Types are not enforced. Add `trusted-types gyral` to the Content-Security-Policy.
```

Arguments: none.

Gyral parses template HTML and `raw()` markup through a Trusted Types policy named `gyral`. The page’s Content-Security-Policy has a `trusted-types` directive that lists allowed policy names without `gyral`, so the browser refused to create it. Gyral falls back to plain strings, which works only while the page doesn’t enforce Trusted Types (`require-trusted-types-for 'script'`). Development warns once.

**Fix:** Add `gyral` to the policy list: `trusted-types gyral` (with your own policies, if any). If you don’t use Trusted Types, remove the `trusted-types` directive.

## Error handling

### G0073

```text
<{tag}> update for "{message}" failed; the state is unchanged.
```

Arguments: `tag`, `message`.

A reducer threw while handling the named message. Nothing changed: the state stays as it was and the commands that reducer would have returned don’t run. It is reported as a `GyralError` (phase `update`), and the component’s `Errored` reducer, if any, receives it.

**Fix:** Fix the exception in that reducer, using the `cause` of the reported error. Add an `Errored` reducer if the component should show an error state ([Error handling](https://gyral.dev/docs/error-handling/)).

### G0074

```text
<{tag}> init failed; it shows its error view, or stays empty.
```

Arguments: `tag`.

A component’s `init` threw, so it has no state. It renders its `error(failure, undefined)` view if its spec has one, or stays empty. The error is reported as a `GyralError` (phase `init`).

**Fix:** Fix the exception in `init`, using the `cause` of the reported error; often a prop or seed read with an unexpected shape. Give the spec an `error` view for a visible fallback.

### G0075

```text
<{tag}> element hook failed; the other hooks still ran.
```

Arguments: `tag`.

An element hook’s `client` function threw. Gyral reported it (phase `hook`) and still ran the other hooks of that render; the element itself is in the DOM.

**Fix:** Fix the exception in the hook, using the `cause` of the reported error.

### G0076

```text
store "{store}": update for "{message}" failed; the state is unchanged.
```

Arguments: `store`, `message`.

A store’s reducer threw while handling the named message. The store’s state is unchanged and its commands don’t run. The error is reported as a `GyralError` (phase `store`); the sender isn’t affected.

**Fix:** Fix the exception in that store reducer, using the `cause` of the reported error.

### G0077

```text
store "{store}": a subscriber failed; the other subscribers were still notified.
```

Arguments: `store`.

A component that reads the store threw while handling `StoreChanged`. The other subscribers were still notified and the store’s commands still ran.

**Fix:** Fix the exception in that component’s `StoreChanged` reducer (or the code it calls), using the `cause` of the reported error.

### G0078

```text
<{tag}> failed to render on the server; it renders its error view (or nothing) and starts fresh in the browser.
```

Arguments: `tag`.

A component’s `init` or view threw during server rendering. It rendered its `error` view (or nothing), marked `data-gyral-error` and without a seed, and the rest of the page was sent; the browser starts that component fresh. `renderPage`’s `onError` received the error.

**Fix:** Fix the exception, using the error your `onError` received. Pass `onError: 'throw'` to `renderPage` if a failing component should fail the whole page instead, so the route can answer with its error page.

## Subscriptions

### G0079

```text
<{tag}> subscriptions returned two commands for lane "{lane}"; only the first runs. Give each its own `key`.
```

Arguments: `tag`, `lane`.

The component’s `subscriptions` returned two commands in the same lane: the same `key`, or no key and the same driver. Gyral keeps one running command per lane, so only the first runs. Development warns.

**Fix:** Give each subscription its own `key`, such as one per room or per URL.

### G0080

```text
<{tag}> subscriptions kept restarting: a subscription's input data changes with every message it sends (for example a timestamp or a counter in the input). Keep inputs to what should restart it; functions are ignored, so to restart on a new selector, change the key.
```

Arguments: `tag`.

A subscription restarted again and again: its input changed with every message it sent, so each new state asked for a different input, which restarted it. Gyral stops after 100 rounds rather than loop.

**Fix:** Keep a subscription’s input to what should restart it (an id, a URL), not values that its own messages change, such as a counter or a timestamp.

## Element calls

### G0085

```text
<{tag}> call("{selector}", "{method}") failed
```

Arguments: `tag`, `selector`, `method`.

A `call(selector, method, …args)` command failed after the render: no element of the component matched the selector, the element has no such method, or the method threw or rejected. The reported error’s `cause` says which. It is reported through the error channel (phase `command`).

**Fix:** Check that the element is rendered when the command runs (return the command from the reducer whose new state renders it), that the selector matches inside the component’s own tree, and that the method exists on that element.

### G0086

```text
call("{selector}", "{method}"): arguments must be plain data.
```

Arguments: `selector`, `method`.

Development checks that a `call()` command’s arguments are plain data that can be cloned (strings, numbers, arrays and plain objects). A function, an element or a class instance would make the command impossible to compare or record in a test.

**Fix:** Pass plain data, and let the element look up anything else itself.
