Errors

MynthAPIError for a rejected request, the TaskAsync errors a wait can throw, and how to read the codes of a task that failed.

The SDK surfaces failures three ways:

What failedWhat you get
The HTTP request was rejectedMynthAPIError is thrown
The task settled as failed, or the wait brokeA TaskAsync* error is thrown
Some items failed on a completed taskNothing is thrown. urls and getImages() are shorter

The codes themselves are on errors. This page is how the SDK reports them.

import Mynth, { MynthAPIError, TaskAsyncTaskFailedError } from "@mynthio/sdk";

const mynth = new Mynth();

const pending = await mynth.image
  .generateAsync({
    model: "black-forest-labs/flux.2-pro",
    prompt: "A lighthouse at dusk, film grain",
  })
  .catch((error: unknown) => {
    if (error instanceof MynthAPIError && error.code === "INSUFFICIENT_BALANCE") {
      // rejected at create: nothing queued, nothing held
    }
    throw error;
  });

try {
  const task = await pending.wait();
  console.log(task.urls[0]);
} catch (error) {
  if (error instanceof TaskAsyncTaskFailedError) {
    // read GET /tasks/{pending.id} for errors[].code
  }
  throw error;
}

Keep the id from generateAsync() before you wait. When generate() throws, the task id is only in the error message, and the error classes have no taskId property.

MynthAPIError#

Thrown for any non-2xx response on a create, upload, estimate, or models call.

PropertyHolds
statusThe HTTP status
codeThe body's code, when there is one
messageThe body's message, or a generic fallback

A schema rejection is status 400 with code undefined and an unhelpful message, because that body has an issue list instead of a code, and the SDK does not keep the list. On error.status === 400 without a code, repeat the request with curl or npx @mynthio/cli ... --json to see which field failed. See schema rejections.

Two failures are not MynthAPIError:

  • A missing API key throws a plain Error when you first read mynth.image or mynth.video.
  • A network failure on the create request throws whatever fetch throws. The create is not retried. There are no idempotency keys, so check GET /tasks before you resend a create that may have gone through.

Errors while waiting#

All are exported from @mynthio/sdk, and none carries a task error code.

ClassThrown when
TaskAsyncTaskFailedErrorThe task settled as failed. The message includes the task id
TaskAsyncTimeoutErrorThe poll budget ran out: 30 minutes for images and tools, one hour for video
TaskAsyncUnauthorizedErrorStatus or the task record answered 401 or 403
TaskAsyncFetchErrorStatus reads kept failing. cause is the last network error, when there was one
TaskAsyncTaskFetchErrorThe task completed, but loading the record kept failing

For TaskAsyncTaskFailedError, read GET /tasks/{id}. Its errors array is [{ code, message? }]. Branch on code.

After TaskAsyncTimeoutError the task is still running on Mynth. Read it by id later instead of creating it again.

RESTRICTED_CONTENT#

A provider refusal usually fails one output, not the task. wait() returns, and urls is shorter than count. Read getImages({ includeFailed: true }) for each error.code. If the refusal failed the whole task, wait() throws TaskAsyncTaskFailedError, and the code is on GET /tasks/{id}. Prompts and images explains the refusal.

Next steps#