Handling errors
Which calls throw, and which don't
Most calls throw when something goes wrong. A few return a value instead, because failure is a normal outcome for them:
| Call | On failure |
|---|---|
Lookups, request(), resource(), collection reads | Throw |
account.gifts.send() | Returns { ok: false, error } |
account.friends.add() / .remove() | Returns false |
account.wishlist.add() / .remove() | Returns false |
account.followers.follow() / .unfollow() | Returns false when the API refuses; other errors throw |
relation() methods such as user.profile(), product.parent() | Return null when the relation doesn't exist |
API errors: IMVUAPIError
When IMVU answers with a failure, @imvu/rest throws IMVUAPIError. Its apiCode is IMVU's machine-readable error code, and message is the human-readable text:
import { IMVUAPIError } from '@imvu/rest';
try {
await client.request(`/user/user-${client.account.id}/friends/user-${id}`, { method: 'DELETE' });
} catch (error) {
if (error instanceof IMVUAPIError) {
console.error(`IMVU refused (${error.apiCode}): ${error.message}`);
console.error(error.response); // the full failure envelope
} else {
throw error; // network failure, a non-JSON response, …
}
}Other errors you may see from the REST layer:
- A network error from
fetchitself (DNS, TLS, offline). Pass asignalin the request options to add timeouts or cancellation. Expected a JSON response …: IMVU answered with something other than JSON, usually an HTML error page during an outage or when blocked.You must be logged into to access account information!: you readclient.accountbeforelogin()finished.
Error codes worth knowing
apiCode | Meaning |
|---|---|
VERIFY-001 | The session must solve a proof-of-work challenge first. Handled for you; see below. |
RATE-001 | Too many messages too fast. Also returned with "verify email" when an unverified account messages non-friends. |
CHAT_PARTICIPANT-001/-002 | The room is full. Room lists lag, so this happens even when it looked open. |
CHAT_PARTICIPANT-004 | The room is unavailable. |
Proof of work
When IMVU decides a session is busy, it rejects requests with VERIFY-001 until the session solves a proof-of-work challenge: a time-lock puzzle that costs CPU time and can't be parallelized. @imvu/client handles this for you, the way the web client does:
- it lists the session's outstanding challenges (
GET /pow); - it solves each one;
- it posts the solutions back;
- it retries the original request, up to
maxPowRetries(3) times.
You'll only see VERIFY-001 if solving keeps failing. With @imvu/rest alone, pass a solver to turn the same behaviour on:
import { REST } from '@imvu/rest';
import { solveRswAsync } from '@imvu/xmlrpc';
const rest = new REST({ proofOfWork: (nonce) => solveRswAsync(nonce) });
await rest.solveChallenges(); // or solve on demand; resolves to how many were handledThe XML-RPC gateway's equivalent, fault 110, is routed to the same challenges by client.xmlrpc.
Gift results
Sending a gift spends credits, so it never throws for an expected failure. It distinguishes rejected (IMVU said no; nothing happened) from indeterminate (the request may or may not have gone through):
const result = await client.account.gifts.send({ recipient, product });
if (!result.ok) {
const { error } = result;
if (error.kind === 'rejected') {
// error.reason: 'insufficient_credits' | 'already_owned' | 'not_giftable'
// | 'recipient_restricted' | 'unknown'
} else {
// 'indeterminate': check before retrying, or you may gift twice.
}
}See Gifting for a complete flow.
Other packages
| Package | Error | When |
|---|---|---|
@imvu/client | CollectionNotWatchableError | watch() on a collection that publishes no updates. |
@imvu/client | RangeError | page() with a negative offset or a non-positive limit. |
@imvu/client | Error | session.send() on a closed ChatSession, or IMQ rejecting a chat line. |
@imvu/verify | RangeError | A challenge secret shorter than 16 bytes. |
@imvu/xmlrpc | XmlRpcFault | The gateway returned a fault. Compare code with FaultCode. |
@imvu/xmlrpc | XmlRpcHttpError | The gateway answered with a non-200 HTTP status. |
@imvu/chkn | ChknError | A malformed CFL/CHKN archive, LZMA stream or product template. |
@imvu/cal3d | Cal3DError | The bytes aren't a Cal3D file, or are corrupt. |
Common XML-RPC fault codes:
import { FaultCode, XmlRpcFault } from '@imvu/xmlrpc';
if (error instanceof XmlRpcFault) {
switch (error.code) {
case FaultCode.InvalidLoginOrPassword: // 11
case FaultCode.TwoFactorRequired: // 107
case FaultCode.InvalidAuthData: // 30: session replaced by another login
case FaultCode.ProofOfWorkRequired: // 110: solved and retried by client.xmlrpc
}
}client.xmlrpc already recovers from InvalidAuthData by logging in once more, so you'll only see it when using XmlRpcGateway directly.