Skip to main content
Le SDK expose deux classes d’erreurs : YoukaRequestError pour les erreurs HTTP et de validation, et YoukaTaskError pour les tâches asynchrones qui se terminent dans un état non réussi. Les deux étendent Error et embarquent des champs structurés afin que vous puissiez brancher sur le code, le statut et la possibilité de retenter.

YoukaRequestError

Levée pour les erreurs HTTP, les échecs de validation de requête et les réponses malformées.
import { YoukaRequestError } from "@youka/sdk";

try {
  await client.projects.create(body);
} catch (error) {
  if (error instanceof YoukaRequestError) {
    console.error({
      code: error.code,
      message: error.message,
      status: error.status,
      retryable: error.retryable,
      details: error.details,
    });
  } else {
    throw error;
  }
}

Champs

code
string
Code d’erreur lisible par machine, par exemple INVALID_REQUEST, UNAUTHORIZED, UPLOAD_FAILED.
message
string
Description lisible par l’humain.
status
number
Code de statut HTTP, si disponible.
retryable
boolean
true si le SDK considère que l’erreur mérite d’être retentée (limites de débit, erreurs serveur transitoires, relecture idempotente en cours).
details
unknown
Détails fournis par le serveur, généralement une liste d’issues Zod pour les erreurs de validation.

Codes courants

CodeCauseRetentable ?
INVALID_REQUESTLe corps de la requête n’a pas passé la validation du schéma avant l’envoi.Non
UNAUTHORIZEDClé API manquante ou invalide.Non
NOT_FOUNDLa ressource n’existe pas ou vous n’y avez pas accès.Non
CONFLICTConflit de version (HTTP 409).Oui
TOO_MANY_REQUESTSLimite de débit atteinte (HTTP 429).Oui
INTERNAL_SERVER_ERRORPanne serveur transitoire (HTTP 500).Oui
IDEMPOTENT_REPLAY_IN_PROGRESSLa requête d’origine est toujours en cours avec la même clé d’idempotence (HTTP 202).Oui
INVALID_RESPONSELe serveur a renvoyé un corps qui ne correspondait pas au schéma attendu.Non
UPLOAD_FAILEDL’upload via l’URL signée a renvoyé un statut non-2xx.Dépend du statut

YoukaTaskError

Levée depuis client.tasks.wait(...), client.projects.wait(...) et client.exports.wait(...) lorsque la tâche ou l’export sous-jacent se termine en failed, cancelled ou timed-out.
import { YoukaTaskError } from "@youka/sdk";

try {
  await client.projects.wait(created);
} catch (error) {
  if (error instanceof YoukaTaskError) {
    console.error({
      code: error.code,
      message: error.message,
      status: error.status,
      task: error.task,
    });
  } else {
    throw error;
  }
}

Champs

code
'TASK_FAILED' | 'TASK_CANCELLED' | 'TASK_TIMED_OUT'
Correspond directement au statut terminal de la tâche.
message
string
Soit le message d’erreur de la tâche fourni par le serveur, soit un message de repli généré.
status
TaskStatus
Le statut terminal de la tâche.
task
RestTask
La charge utile complète de la tâche au moment de l’échec. Utile pour la journalisation et les messages d’erreur destinés à l’utilisateur.

Modèle de retry

Combinez retryable avec une clé d’idempotence pour construire une boucle de retry sûre :
import { YoukaRequestError } from "@youka/sdk";

async function createWithRetry<T>(fn: () => Promise<T>, maxAttempts = 3) {
  let lastError: unknown;

  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      return await fn();
    } catch (error) {
      lastError = error;
      if (
        error instanceof YoukaRequestError &&
        error.retryable &&
        attempt < maxAttempts
      ) {
        await new Promise((r) => setTimeout(r, 2 ** attempt * 1_000));
        continue;
      }
      throw error;
    }
  }

  throw lastError;
}

await createWithRetry(() =>
  client.projects.create(body, {
    idempotencyKey: "import-2026-04-08-song-001",
  }),
);
Réutilisez toujours la même clé d’idempotence lors des retries. Sinon le serveur traite le retry comme une nouvelle requête et vous risquez d’obtenir des doublons.

Abandon et annulation

L’abandon d’une requête lève un AbortError standard — pas un YoukaRequestError. Vérifiez-le explicitement :
try {
  await client.projects.wait(created, { signal: controller.signal });
} catch (error) {
  if (error instanceof Error && error.name === "AbortError") {
    console.log("Cancelled by user");
    return;
  }
  throw error;
}

Et ensuite