Handling errors
The broker is the connection your page holds into FKN. A call that reaches it is answered in another JavaScript context, so the error you catch is only what survived the trip back. This page covers which fields of an error survive, which two errors keep a class, how to test the rest, and which failures are worth retrying.
See also
Section titled “See also”What crosses a realm
Section titled “What crosses a realm”The broker runs in another realm. A realm is one JavaScript execution context, such as a window or a worker. The library mounts a hidden fkn.app iframe, the broker frame, and behind that frame runs a shared worker, the data plane, where the call is served.
An error thrown in the data plane crosses two hops before you catch it: one into the broker frame and one into your realm. Each hop carries name, message, stack and cause and nothing else. The hops are described under how it works.
A read while the storage api is not answering shows what arrives:
try { await (alias) namespace cloudimport cloud
cloud.namespace cloud_d_exports.fsexport cloud_d_exports.fs
fs.const fs_d_exports.promises: { readFile: (path: import("node:fs").PathLike, options?: ReadOptions) => Promise<Buffer | string>; writeFile: (path: import("node:fs").PathLike, data: WriteData, options?: WriteOptions) => Promise<void>; unlink: (path: import("node:fs").PathLike) => Promise<void>; rename: (from: import("node:fs").PathLike, to: import("node:fs").PathLike) => Promise<void>; readdir: (path: import("node:fs").PathLike) => Promise<string[]>; mkdir: (_path?: import("node:fs").PathLike, _options?: MakeOptions) => Promise<void>; ... 4 more ...; access: (path: import("node:fs").PathLike) => Promise<void>;}export fs_d_exports.promises
promises.readFile: (path: import("node:fs").PathLike, options?: ReadOptions) => Promise<Buffer | string>
readFile('library/catalog.json', 'utf8')} catch (var error: unknown
error) { const { const name: string
name, const message: string
message, const code: string | undefined
code } = var error: unknown
error as interface Error
Error & { code?: string | undefined
code?: string } const name: string
name // 'Error', so there is no class to test, only the sentence const message: string
message // 'storage: api unreachable', the prefix you match const code: string | undefined
code // undefined, set beside that sentence in the data plane and gone by here}Three things follow from that:
instanceofdoes not work across a hop. The class the broker threw is not a constructor in your realm.- A custom
codedoes not arrive. The data plane sets one besidestorage: api unreachable, and only the message prefix reaches you. namesurvives. The FKN browser extension and the locators identify their refusals by it.
An error created in your own realm keeps every field. BrokerUnreachableError is a class, so you can test it with instanceof. The library throws it when no broker connection settles within the 8,000 ms broker deadline, or within 1,000 ms once any call in the realm has already missed that deadline.
The ENOENT family on the node-style members of fs, opfs and cloud.fs carries a real code. So does PackagesError, which is a type rather than a class, so its code is the field to test. Both are listed under TypeScript. opfs never reaches the broker, so its errors are ordinary same-realm errors, as described under entry points.
Two errors keep a class
Section titled “Two errors keep a class”StorageLockedError and StorageNotFoundError are the two exceptions. The library catches every cloud.fs read and write rejection on your side and, for those two, throws a fresh error of its own class with a code. That step is the re-mint.
StorageLockedError replaces an error whose message carries the broker’s fkn:e2e-locked prefix. StorageNotFoundError replaces an error whose code already reads FKN_STORAGE_NOT_FOUND, or, failing that, one whose message reads Not found or ends in (404).
A missing file is reported in two wordings. When the api refuses to presign a path that has no committed row, the message is Not found. When the presign succeeds and the object itself answers 404, the message is storage: read failed (404).
An app that matched only the first wording treated a missing backup as a transient failure and retried forever. isNotFound covers both:
import { const isNotFound: (error: unknown) => boolean
Whether an error from this module means the path is empty, as opposed to unreadable.
isNotFound, class StorageLockedError
StorageLockedError } from '@fkn/lib/cloud/fs'
try { await (alias) namespace cloudimport cloud
cloud.namespace cloud_d_exports.fsexport cloud_d_exports.fs
fs.const fs_d_exports.promises: { readFile: (path: import("node:fs").PathLike, options?: ReadOptions) => Promise<Buffer | string>; writeFile: (path: import("node:fs").PathLike, data: WriteData, options?: WriteOptions) => Promise<void>; unlink: (path: import("node:fs").PathLike) => Promise<void>; rename: (from: import("node:fs").PathLike, to: import("node:fs").PathLike) => Promise<void>; readdir: (path: import("node:fs").PathLike) => Promise<string[]>; mkdir: (_path?: import("node:fs").PathLike, _options?: MakeOptions) => Promise<void>; ... 4 more ...; access: (path: import("node:fs").PathLike) => Promise<void>;}export fs_d_exports.promises
promises.readFile: (path: import("node:fs").PathLike, options?: ReadOptions) => Promise<Buffer | string>
readFile('backup/library.bin')} catch (var error: unknown
error) { function isNotFound(error: unknown): boolean
Whether an error from this module means the path is empty, as opposed to unreadable.
isNotFound(var error: unknown
error) // true for both 'Not found' and 'storage: read failed (404)' var error: unknown
error instanceof class StorageLockedError
StorageLockedError // false, locked is its own class and never reads as absence}isNotFound answers true for both wordings. StorageLockedError carries storage locked: this account stores encrypted data, unlock it from the FKN card or unlock(), a sentence that matches neither on purpose. The difference matters: a path with nothing at it is safe to write a first backup to, and a path you could not read is not.
The order to test in
Section titled “The order to test in”Test in the order the errors were created. The two classes come first, then the message prefixes, then the names, and last the one class that never crossed a hop:
import { (alias) namespace cloudimport cloud
cloud, const isLocatorDenied: (error: unknown) => boolean
isLocatorDenied, const isTerminalError: (error: unknown) => boolean
isTerminalError } from '@fkn/lib'import { const isNotFound: (error: unknown) => boolean
Whether an error from this module means the path is empty, as opposed to unreadable.
isNotFound, class StorageLockedError
StorageLockedError } from '@fkn/lib/cloud/fs'import { const E2E_INTEGRITY_MESSAGE: "fkn:e2e-integrity: stored data failed its integrity check"
E2E_INTEGRITY_MESSAGE, const E2E_STALE_EPOCH_MESSAGE: "fkn:e2e-stale-epoch: this file is encrypted under a previous key you reset"
E2E_STALE_EPOCH_MESSAGE } from '@fkn/lib/messages'
const const handle: (error: unknown) => Promise<null> | Promise<string | Buffer<ArrayBufferLike>> | null
handle = (error: unknown
error: unknown) => { // absence and locked, minted in your realm if (function isNotFound(error: unknown): boolean
Whether an error from this module means the path is empty, as opposed to unreadable.
isNotFound(error: unknown
error)) return null // start empty if (error: unknown
error instanceof class StorageLockedError
StorageLockedError) return const promptUnlock: () => Promise<null>
promptUnlock() // ask, then read again
// the rest of the broker's errors, by prefix const const message: string
message = error: unknown
error instanceof var Error: ErrorConstructor
Error ? error: Error
error.Error.message: string
message : '' if (const message: string
message.String.startsWith(searchString: string, position?: number): boolean
Returns true if the sequence of elements of searchString converted to a String is the
same as the corresponding elements of this object (converted to a String) starting at
position. Otherwise returns false.
startsWith(const E2E_STALE_EPOCH_MESSAGE: "fkn:e2e-stale-epoch: this file is encrypted under a previous key you reset"
E2E_STALE_EPOCH_MESSAGE)) throw error: unknown
error // never retry, never overwrite if (const message: string
message.String.startsWith(searchString: string, position?: number): boolean
Returns true if the sequence of elements of searchString converted to a String is the
same as the corresponding elements of this object (converted to a String) starting at
position. Otherwise returns false.
startsWith(const E2E_INTEGRITY_MESSAGE: "fkn:e2e-integrity: stored data failed its integrity check"
E2E_INTEGRITY_MESSAGE)) throw error: unknown
error // never overwrite if (const message: string
message.String.startsWith(searchString: string, position?: number): boolean
Returns true if the sequence of elements of searchString converted to a String is the
same as the corresponding elements of this object (converted to a String) starting at
position. Otherwise returns false.
startsWith('storage: api unreachable')) return const keepLocalCopy: () => null
keepLocalCopy() // retry later if (const message: string
message.String.startsWith(searchString: string, position?: number): boolean
Returns true if the sequence of elements of searchString converted to a String is the
same as the corresponding elements of this object (converted to a String) starting at
position. Otherwise returns false.
startsWith('FKN: the broker was replaced')) return const retryOnce: () => Promise<string | Buffer>
retryOnce() // routed to the new broker already
// locators and frames, by name, through the guards if (function isLocatorDenied(error: unknown): boolean
isLocatorDenied(error: unknown
error)) return const explainRefusal: () => null
explainRefusal() // a gate said no if (function isTerminalError(error: unknown): boolean
isTerminalError(error: unknown
error)) return const giveUp: () => null
giveUp() // retrying changes nothing
// the consent refusal, its own name, matched by neither guard if (error: unknown
error instanceof var Error: ErrorConstructor
Error && error: Error
error.Error.name: string
name === 'PermissionDeniedError') return const explainRefusal: () => null
explainRefusal()
// the broker deadline, a class minted here if (error: unknown
error instanceof class BrokerUnreachableError
BrokerUnreachableError) return const waitAndRetry: () => Promise<string | Buffer>
waitAndRetry()
throw error: unknown
error}
const const catalog: string | Buffer<ArrayBufferLike> | null
catalog = await (alias) namespace cloudimport cloud
cloud.namespace cloud_d_exports.fsexport cloud_d_exports.fs
fs.const fs_d_exports.promises: { readFile: (path: import("node:fs").PathLike, options?: ReadOptions) => Promise<Buffer | string>; writeFile: (path: import("node:fs").PathLike, data: WriteData, options?: WriteOptions) => Promise<void>; unlink: (path: import("node:fs").PathLike) => Promise<void>; rename: (from: import("node:fs").PathLike, to: import("node:fs").PathLike) => Promise<void>; readdir: (path: import("node:fs").PathLike) => Promise<string[]>; mkdir: (_path?: import("node:fs").PathLike, _options?: MakeOptions) => Promise<void>; ... 4 more ...; access: (path: import("node:fs").PathLike) => Promise<void>;}export fs_d_exports.promises
promises.readFile: (path: import("node:fs").PathLike, options?: ReadOptions) => Promise<Buffer | string>
readFile('library/catalog.json', 'utf8').Promise<string | Buffer<ArrayBufferLike>>.catch<string | Buffer<ArrayBufferLike> | null>(onrejected?: ((reason: any) => string | Buffer<ArrayBufferLike> | PromiseLike<string | Buffer<ArrayBufferLike> | null> | null) | null | undefined): Promise<string | Buffer<ArrayBufferLike> | null>
Attaches a callback for only the rejection of the Promise.
catch(const handle: (error: unknown) => Promise<null> | Promise<string | Buffer<ArrayBufferLike>> | null
handle) // the catalog, or nullThe two classes come first because they carry the only code a cloud.fs rejection can be trusted to have. The prefix branch compares sentences because the E2E_* constants from @fkn/lib/messages and the two fixed prefixes are exactly what the broker sends. The constants are described under encryption, and every message has a row on every error.
A refusal neither guard matches
Section titled “A refusal neither guard matches”The consent sheet is the prompt the extension shows before an action that needs the user’s approval. When the user refuses there, the extension rejects with Permission denied: <key> (<scope>) under the name PermissionDeniedError. Neither locator guard looks for that name:
try { await const frame: Frame
frame.locator: (selector: string) => Locator$1<Extended<{ readonly element: { readonly selectors: { readonly locator: { readonly to: "element"; readonly css: true; readonly resolve: (context: LocatorContext, selector: string) => Element[]; readonly render: (selector: unknown) => { fragment: string; separator: "descend"; }; }; readonly frameLocator: { readonly to: "frame"; readonly css: true; readonly barrier: "down"; readonly resolve: (context: LocatorContext, selector: string) => Element[]; readonly render: (selector: unknown) => { fragment: string; separator: "down"; }; }; readonly getByRole: { readonly to: "element"; readonly resolve: (context: LocatorContext, role: string) => Element[]; readonly render: (role: unknown) => { fragment: string; }; }; readonly getByText: { readonly to: "element"; readonly resolve: (context: LocatorContext, text: string) => Element[]; readonly render: (text: unknown) => { fragment: string; }; }; readonly getByTestId: { readonly to: "element"; readonly resolve: (context: LocatorContext, testId: string) => Element[]; readonly render: (testId: unknown) => { fragment: string; }; }; readonly first: { readonly to: "element"; readonly resolve: (context: LocatorContext) => Element[]; readonly render: () => { fragment: string; }; }; readonly nth: { readonly to: "element"; readonly resolve: (context: LocatorContext, index: number) => Element[]; readonly render: (index: unknown) => { fragment: string; }; }; }; readonly operations: { readonly click: { readonly resolve: (context: LocatorContext, options?: PositionOptions$1) => void; }; readonly fill: { readonly resolve: (context: LocatorContext, value: string, _options?: OperationOptions) => void; }; readonly hover: { readonly resolve: (context: LocatorContext, options?: PositionOptions$1) => void; }; readonly textContent: { readonly resolve: (context: LocatorContext, _options?: OperationOptions) => string; }; readonly getAttribute: { readonly resolve: (context: LocatorContext, name: string, _options?: OperationOptions) => string | null; }; readonly isVisible: { readonly resolve: (context: LocatorContext, _options?: OperationOptions) => boolean; }; readonly count: { readonly resolve: (context: LocatorContext, _options?: OperationOptions) => number; }; readonly exists: { readonly resolve: (context: LocatorContext, _options?: OperationOptions) => boolean; }; }; }; readonly frame: { readonly selectors: { readonly locator: { readonly to: "element"; readonly css: true; readonly resolve: (context: LocatorContext, selector: string) => Element[]; readonly render: (selector: unknown) => { fragment: string; separator: "descend"; }; }; readonly frameLocator: { readonly to: "frame"; readonly css: true; readonly barrier: "down"; readonly resolve: (context: LocatorContext, selector: string) => Element[]; readonly render: (selector: unknown) => { fragment: string; separator: "down"; }; }; readonly owner: { readonly to: "frame"; readonly barrier: "up"; readonly resolve: (_context: LocatorContext) => Element[]; readonly render: () => { fragment: string; separator: "up"; }; }; }; readonly operations: { readonly addStyleTag: { readonly resolve: (context: LocatorContext, options: AddStyleTagOptions$1) => void; }; readonly fetch: { readonly kind: ChainKind; readonly ...
locator('#play').click: (options?: PositionOptions | undefined) => Promise<void>
click({ reason?: string | undefined
reason: 'Start the trailer' })} catch (var error: unknown
error) { const { const name: string
name, const message: string
message } = var error: unknown
error as interface Error
Error function isLocatorDenied(error: unknown): boolean
isLocatorDenied(var error: unknown
error) // false, even though the user refused const name: string
name // 'PermissionDeniedError' const message: string
message // 'Permission denied: act.click (#play)'}The refusal is still terminal. The consent sheet raises it before the retry loop starts, but only the name test above tells you so. The keys and scopes are described under permissions and consent.
The name with no constant
Section titled “The name with no constant”@fkn/lib re-exports the constants LOCATOR_DENIED, LOCATOR_ERROR and LOCATOR_UNSUPPORTED and the guards isLocatorDenied, isLocatorUnsupported and isTerminalError. It does not export LOCATOR_INVALID, isLocatorInvalid or locatorInvalidError. isTerminalError still matches the invalid name. The guard reads nothing but the name, so an error built with that name is enough to show it:
import { isLocatorInvalid } from '@fkn/lib'Error ts(2305) ―
const const invalid: Error & { name: string;}
invalid = var Object: ObjectConstructor
Provides functionality common to all JavaScript objects.
Object.ObjectConstructor.assign<Error, { name: string;}>(target: Error, source: { name: string;}): Error & { name: string;} (+3 overloads)
Copy the values of all of the enumerable own properties from one or more source objects to a
target object. Returns the target object.
assign(new var Error: ErrorConstructornew (message?: string, options?: ErrorOptions) => Error (+1 overload)
Error('fetch: url must be a string'), { name: string
name: 'LocatorInvalidError' })function isTerminalError(error: unknown): boolean
isTerminalError(const invalid: Error & { name: string;}
invalid) // true, the invalid name stops the loop like the other twoUse the guard rather than comparing against a name whose constant you cannot import. The locator errors are described under locators and actions.
What a timeout says
Section titled “What a timeout says”A locator action retries every failed attempt until its deadline, which is 30,000 ms unless you pass timeout. It then rethrows the last attempt’s error. For a missing element that error is No elements found:
try { await const frame: Frame
frame.locator: (selector: string) => Locator$1<Extended<{ readonly element: { readonly selectors: { readonly locator: { readonly to: "element"; readonly css: true; readonly resolve: (context: LocatorContext, selector: string) => Element[]; readonly render: (selector: unknown) => { fragment: string; separator: "descend"; }; }; readonly frameLocator: { readonly to: "frame"; readonly css: true; readonly barrier: "down"; readonly resolve: (context: LocatorContext, selector: string) => Element[]; readonly render: (selector: unknown) => { fragment: string; separator: "down"; }; }; readonly getByRole: { readonly to: "element"; readonly resolve: (context: LocatorContext, role: string) => Element[]; readonly render: (role: unknown) => { fragment: string; }; }; readonly getByText: { readonly to: "element"; readonly resolve: (context: LocatorContext, text: string) => Element[]; readonly render: (text: unknown) => { fragment: string; }; }; readonly getByTestId: { readonly to: "element"; readonly resolve: (context: LocatorContext, testId: string) => Element[]; readonly render: (testId: unknown) => { fragment: string; }; }; readonly first: { readonly to: "element"; readonly resolve: (context: LocatorContext) => Element[]; readonly render: () => { fragment: string; }; }; readonly nth: { readonly to: "element"; readonly resolve: (context: LocatorContext, index: number) => Element[]; readonly render: (index: unknown) => { fragment: string; }; }; }; readonly operations: { readonly click: { readonly resolve: (context: LocatorContext, options?: PositionOptions$1) => void; }; readonly fill: { readonly resolve: (context: LocatorContext, value: string, _options?: OperationOptions) => void; }; readonly hover: { readonly resolve: (context: LocatorContext, options?: PositionOptions$1) => void; }; readonly textContent: { readonly resolve: (context: LocatorContext, _options?: OperationOptions) => string; }; readonly getAttribute: { readonly resolve: (context: LocatorContext, name: string, _options?: OperationOptions) => string | null; }; readonly isVisible: { readonly resolve: (context: LocatorContext, _options?: OperationOptions) => boolean; }; readonly count: { readonly resolve: (context: LocatorContext, _options?: OperationOptions) => number; }; readonly exists: { readonly resolve: (context: LocatorContext, _options?: OperationOptions) => boolean; }; }; }; readonly frame: { readonly selectors: { readonly locator: { readonly to: "element"; readonly css: true; readonly resolve: (context: LocatorContext, selector: string) => Element[]; readonly render: (selector: unknown) => { fragment: string; separator: "descend"; }; }; readonly frameLocator: { readonly to: "frame"; readonly css: true; readonly barrier: "down"; readonly resolve: (context: LocatorContext, selector: string) => Element[]; readonly render: (selector: unknown) => { fragment: string; separator: "down"; }; }; readonly owner: { readonly to: "frame"; readonly barrier: "up"; readonly resolve: (_context: LocatorContext) => Element[]; readonly render: () => { fragment: string; separator: "up"; }; }; }; readonly operations: { readonly addStyleTag: { readonly resolve: (context: LocatorContext, options: AddStyleTagOptions$1) => void; }; readonly fetch: { readonly kind: ChainKind; readonly ...
locator('h1').textContent: (_options?: LocatorOptions | undefined) => Promise<string>
textContent()} catch (var error: unknown
error) { const { const name: string
name, const message: string
message } = var error: unknown
error as interface Error
Error const message: string
message // 'No elements found', after 30 seconds const name: string
name // 'LocatorError', the last attempt's error rather than a timeout}Locator timeout (30000ms): textContent appears only when no attempt failed before the deadline. A handler that waits for the word timeout will not see it after a missing element.
unlink() skips the re-mint
Section titled “unlink() skips the re-mint”The re-mint wraps cloud.fs reads and writes only. The deletes, unlink, rm and rmdir, are not wrapped, in the promise form and the callback form alike. Deleting a missing path therefore rejects with the api’s own Not found, and isNotFound answers false:
import { const isNotFound: (error: unknown) => boolean
Whether an error from this module means the path is empty, as opposed to unreadable.
isNotFound } from '@fkn/lib/cloud/fs'
try { await (alias) namespace cloudimport cloud
cloud.namespace cloud_d_exports.fsexport cloud_d_exports.fs
fs.const fs_d_exports.promises: { readFile: (path: import("node:fs").PathLike, options?: ReadOptions) => Promise<Buffer | string>; writeFile: (path: import("node:fs").PathLike, data: WriteData, options?: WriteOptions) => Promise<void>; unlink: (path: import("node:fs").PathLike) => Promise<void>; rename: (from: import("node:fs").PathLike, to: import("node:fs").PathLike) => Promise<void>; readdir: (path: import("node:fs").PathLike) => Promise<string[]>; mkdir: (_path?: import("node:fs").PathLike, _options?: MakeOptions) => Promise<void>; ... 4 more ...; access: (path: import("node:fs").PathLike) => Promise<void>;}export fs_d_exports.promises
promises.unlink: (path: import("node:fs").PathLike) => Promise<void>
unlink('backup/library.bin')} catch (var error: unknown
error) { const { const message: string
message } = var error: unknown
error as interface Error
Error const message: string
message // 'Not found', the api's own sentence function isNotFound(error: unknown): boolean
Whether an error from this module means the path is empty, as opposed to unreadable.
isNotFound(var error: unknown
error) // false, unlink does not run the re-mint}A recursive rm goes further: it swallows the failure of every object under the path and reports nothing at all. For a delete, match the message or treat any failure as best effort. Deletes are described under storage.
Which failures are worth retrying
Section titled “Which failures are worth retrying”One row per group of every error, with the test for that group and whether the same call can succeed later:
| Group | What to test | Retry |
|---|---|---|
| Fetch | a refusal from the library or the extension rejects, so wrap the call. A refusal from the proxy, the server cloud.fetch sends a request through, arrives as a resolved Response, so check response.ok and the body’s error | a 429 or a 502 in the body, or no proxy being available, never a refused target |
| Sockets | an argument or state refusal throws at the call, and a connect, bind or listen failure arrives as the message prefix on the error event | a timed-out connect or a capacity ceiling, never a refused address |
| Storage | isNotFound(), instanceof StorageLockedError, then the storage: prefix | unreachable and Concurrent update, retry, locked after unlock(), never absence |
| Encryption | the three E2E_* prefixes, then the api’s own sentences | never on fkn:e2e-stale-epoch or fkn:e2e-integrity, a write refused with Superseded key at once, and one refused with This account has no encryption keys yet after re-enrolling |
| Frames | the message prefix, then isTerminalError() | a timed-out handshake or goto, never a refusal |
| Locators | isLocatorDenied(), isTerminalError(), then error.name | not for a plain LocatorError, which the loop already retried, and not for a terminal name, which was never retried and will not change |
| Permissions | error.name === 'PermissionDeniedError' | only through the user |
| Packages | error.code | a timeout or an unavailable, and an invalid only after fixing the argument it names |
| Broker | instanceof BrokerUnreachableError, then the FKN: the broker was replaced prefix | the class after a wait, and the replaced broker once. A relayWorker refusal needs the realm fixed rather than a retry |
Several rows describe an integration working as intended, such as a refusal at the consent sheet or a missing first backup. Handle those as answers rather than failures.
Errors you might see
Section titled “Errors you might see”The six broker and lifecycle rows, each with its cause and its fix:
| Message | What happened | What to do |
|---|---|---|
@fkn/lib: no broker connection within <ms>ms, so <what> could not be requested | No broker connection settled inside the deadline of 8,000 ms, or 1,000 ms after a miss. The usual cause is a worker nobody relayed. | Call await relayWorker(worker, { unregisterSignal }) from the page, as shown under workers. |
FKN: the broker was replaced while this call was pending; retry it | An update of the shell, the FKN surface that can update and reload the page, reloaded the broker frame while a call was in flight. | Retry once. The replacement is described under errors and lifecycle. |
FKN @fkn/lib: relayWorker must be called from the main thread | relayWorker ran inside a worker. | Call it from the page. |
FKN @fkn/lib: relayWorker found no FKN transport in this realm | This realm holds neither a mounted broker frame nor a port from a parent FKN realm. | Import the library on a page that mounts the broker frame first, as described under how it works. |
storage: api unreachable | The storage api never answered at all, which is different from the api answering with an error. | Keep the local copy and retry later. |
webvpn: socket capacity reached | The relay, the server that holds the real socket for net and dgram, reached a capacity ceiling. | Close a socket this app holds to free a slot. The ceilings are listed under limits and timeouts. |
Every other message has a row on every error. The calls that wait with no deadline are listed on errors and lifecycle.