Docs do Nodaro
DocumentaçãoReferência de nósModelosAgentes de IA (MCP)DesenvolvedoresSelf-hostingPesquisa
SDK para TypeScript

Erros

Todos os erros do SDK do Nodaro para TypeScript, com status HTTP, código e campos, e o que fazer com créditos, limites de taxa, conflitos e jobs com falha.

Todo erro que o SDK do Nodaro lança para uma resposta da API é uma instância de NodaroError ou de uma das subclasses dele. Uma requisição que falha com um status de erro lança a subclasse correspondente ao status. Os helpers que executam e esperam lançam subclasses próprias quando um job falha, excede o tempo limite ou é interrompido. Capture primeiro as classes específicas e NodaroError por último.

Todas as classes de erro

ClasseStatuscodeCampos extrasQuando é lançado
NodaroErrorQualquer umO código do servidorA classe base, e qualquer erro sem uma classe mais específica
UnauthorizedError401unauthorizedO token está ausente, expirou ou é inválido
ForbiddenError403forbiddenmissingScope?A permissão foi negada, ou falta um escopo a um token OAuth
NotFoundError404not_foundO item não existe, ou você não pode vê-lo
RateLimitedError429rate_limitedRequisições demais
InsufficientCreditsError402insufficient_creditsrequired?, available?A conta não consegue pagar a execução
StorageExceededError413storage_exceededlimitBytes?O armazenamento da conta está cheio
WorkflowConflictError409workflow_conflict ou production_busycurrentUpdatedAt?, currentVersion?, currentRecord?Outra pessoa alterou o item antes
JobBlockedError422job_blockedA política de conteúdo da implantação recusou a requisição
StudioOpError4xxO código do servidoropIndexUma operação de um lote do Studio foi recusada
JobFailedError0job_failedjobId, jobStatusUm job que você estava esperando falhou ou foi cancelado
JobTimeoutError0job_timeoutjobId, timeoutMsUm job não terminou dentro de maxMs
JobAbortedError0job_abortedjobId?Seu AbortSignal foi acionado durante a espera
JobHeldError0job_heldjobIdUm job está retido para revisão humana
StudioPreviewUnavailable0studio_preview_unavailableA implantação não consegue gerar a prévia de um lote do Studio
StudioPreviewAppliedError0studio_preview_appliedappliedUm lote do Studio do qual você pediu a prévia foi aplicado

Toda classe tem três campos: message, uma frase legível; code, uma string estável que você pode comparar; e status, o status HTTP. Um status igual a 0 significa que o erro não veio de uma resposta HTTP. Por exemplo, JobTimeoutError é lançado pelo próprio loop de consulta periódica do SDK.

Alguns status correspondem a uma única classe, seja qual for o código que o servidor enviou. Um 403 vira ForbiddenError com code igual a forbidden, e um 404 vira NotFoundError. Nesses casos, leia message para saber o motivo do servidor. Um 409 só vira WorkflowConflictError com o código workflow_conflict ou production_busy. Erros com qualquer outro status, como 400 ou 503, e um 409 com qualquer outro código chegam como NodaroError com o code do próprio servidor.

Capturar os erros em ordem

import {
  ForbiddenError,
  InsufficientCreditsError,
  NodaroError,
  NotFoundError,
  RateLimitedError,
  StorageExceededError,
  UnauthorizedError,
} from "@nodaro/sdk"

try {
  await client.workflows.run(workflowId)
} catch (err) {
  if (err instanceof UnauthorizedError) {
    redirectToLogin()
  } else if (err instanceof ForbiddenError) {
    if (err.missingScope) requestAdditionalScopes([err.missingScope])
    else showError("You do not have permission to do this.")
  } else if (err instanceof InsufficientCreditsError) {
    showCreditPaywall({ required: err.required, available: err.available })
  } else if (err instanceof RateLimitedError) {
    await retryWithBackoff()
  } else if (err instanceof StorageExceededError) {
    showError(`Storage limit of ${err.limitBytes} bytes reached.`)
  } else if (err instanceof NotFoundError) {
    showError("Not found.")
  } else if (err instanceof NodaroError) {
    console.error(`API error ${err.status} (${err.code}): ${err.message}`)
  } else {
    throw err // a network failure or a timeout, not an API answer
  }
}

Uma requisição que excede o timeoutMs do cliente e uma falha de rede são rejeitadas com o erro do próprio runtime, como um AbortError ou um TypeError. Esses erros não são instâncias de NodaroError.

Autenticação e permissão

UnauthorizedError

HTTP 401. O token está ausente, expirou ou é inválido. Obtenha um novo token ou faça o usuário entrar de novo e, depois, tente outra vez.

ForbiddenError

HTTP 403. Quem chamou não tem permissão para isso. Quando um token OAuth não recebeu um escopo de que o endpoint precisa, missingScope indica esse escopo, por exemplo workflows:execute. Peça ao usuário que o aprove e tente de novo com o novo token. Veja Escopos e permissões ausentes.

Outros motivos incluem uma edição que não oferece o recurso e uma função abaixo da necessária. Todos chegam com code igual a forbidden, então mostre message para explicar qual é o caso.

NotFoundError

HTTP 404. O item não existe ou não está visível para quem chamou. O Nodaro responde da mesma forma nos dois casos, então um ID nunca revela se existe algo que você não pode ver. Um recurso que só existe no Nodaro Cloud, como as produções do Studio ou o Recast, também responde 404 em uma instalação self-hosted.

Créditos, armazenamento e limites

InsufficientCreditsError

HTTP 402. A conta não consegue pagar a execução, então nada foi iniciado. required é o número de créditos que a execução exige, e available é o número que a conta tem. O Nodaro Cloud preenche os dois, mas o tipo os marca como opcionais.

try {
  await client.nodes.runAndWait("generate-video", params)
} catch (err) {
  if (err instanceof InsufficientCreditsError) {
    console.log(`Need ${err.required} credits, have ${err.available}`)
  }
}

Leia o saldo antes de uma execução com client.credits.balance(). Veja Créditos.

StorageExceededError

HTTP 413. A conta atingiu o limite de armazenamento, e limitBytes é esse limite. Uploads e cópias para o seu armazenamento, como um clone da comunidade, lançam esse erro. Exclua as mídias de que você não precisa mais e tente de novo.

RateLimitedError

HTTP 429. Você enviou requisições demais. Espere e tente de novo com uma pausa crescente: por exemplo, 2 segundos, depois 4, depois 8. Pare depois de algumas tentativas. Veja Limites de taxa.

Espera por jobs

client.nodes.runAndWait(), client.nodes.runMany() e os helpers ...AndWait de outros recursos consultam um job periodicamente até ele terminar. Eles lançam estes erros durante a espera.

JobFailedError

O job terminou com o status failed ou cancelled. jobStatus diz qual dos dois, jobId identifica o job, e message traz a mensagem de erro do próprio job. Leia o job completo com client.jobs.get(err.jobId): o error_hint dele explica um bloqueio de segurança ou de política.

JobTimeoutError

O job não chegou a um estado final dentro de maxMs, que por padrão é de 15 minutos. O job não é cancelado. Em geral, ele termina mesmo assim no servidor e vai para a sua biblioteca. Busque o job mais tarde com client.jobs.get(err.jobId) ou passe um maxMs maior para modelos lentos. Um job que a plataforma está recuperando informa recovering: true no status, e a recuperação pode levar dezenas de minutos.

JobAbortedError

Seu AbortSignal foi acionado. O SDK interrompe a consulta periódica na hora. O job não é cancelado. Para interrompê-lo no servidor e reembolsar os créditos reservados, chame client.jobs.cancel(err.jobId).

JobHeldError

O job chegou ao status pending_review: uma política de conteúdo desta implantação reteve o resultado para que uma pessoa o revise. O SDK para de esperar na primeira consulta que vê esse status. O job não é cancelado, e os créditos dele continuam reservados durante a revisão. Não execute a requisição de novo, porque uma duplicata também seria retida.

Verifique o job mais tarde com client.jobs.get(err.jobId). Ele termina em completed quando o revisor o aprova, em failed quando o revisor o rejeita, ou em cancelled se você o cancelar. Um job rejeitado traz error_hint.kind igual a policy-block e um reason que você pode mostrar como está. Este erro só ocorre em implantações que registram uma política de jobs.

JobBlockedError

HTTP 422 com o código job_blocked. Uma política de conteúdo desta implantação recusou a requisição antes da execução. Nenhum job foi criado e nada foi cobrado. message foi escrita para os seus usuários, então mostre-a como está. Não tente a mesma requisição de novo. Este erro só ocorre em implantações que registram uma política de jobs.

Alterações simultâneas

WorkflowConflictError

HTTP 409. Você fez uma alteração condicional, e outra pessoa alterou o item antes. Ele chega com um destes dois códigos:

  • workflow_conflict: um client.workflows.update() com expectedVersion ou expectedUpdatedAt não correspondeu ao workflow armazenado.
  • production_busy: uma produção do Studio continuou mudando enquanto o servidor aplicava a sua alteração, e o servidor parou de tentar.

A solução é a mesma para os dois: leia o item de novo, aplique sua alteração à cópia atualizada e envie de novo. Quando o servidor o inclui, currentRecord contém o workflow atual, então você pode mesclar sem outra leitura.

import { WorkflowConflictError } from "@nodaro/sdk"

try {
  await client.workflows.update(id, { settings, expectedVersion: loadedVersion })
} catch (err) {
  if (err instanceof WorkflowConflictError && err.currentRecord) {
    const merged = mergeSettings(err.currentRecord.settings, settings)
    await client.workflows.update(id, { settings: merged, expectedVersion: err.currentVersion })
  } else {
    throw err
  }
}

Locais e objetos usam um código de conflito próprio, concurrent_modification, que chega como um NodaroError simples. Trate-o da mesma forma: leia o item de novo, mescle e tente outra vez.

Lotes do Studio

Estas três classes pertencem às produções do Studio.

  • StudioOpError: um lote de operações foi recusado, e opIndex é a posição, contada a partir de zero, da operação que causou a recusa. Nada do lote foi gravado. Corrija essa operação e envie o lote inteiro de novo.
  • StudioPreviewUnavailable: você pediu uma prévia com dryRun: true, e esta implantação não consegue gerá-la. Seu lote não foi enviado. Avise o usuário de que a prévia não está disponível e não aplique o lote sem perguntar.
  • StudioPreviewAppliedError: você pediu uma prévia, e o lote foi aplicado mesmo assim. Trate applied.production e applied.version como o estado atual. Não envie o lote de novo. Quando applied for undefined, leia a produção de novo antes de decidir qualquer coisa.

Códigos que podem aparecer em NodaroError

Estes códigos chegam em um NodaroError simples. Compare err.code para tratá-los.

StatusCódigoOndeSignificado
400validation_errorMuitos métodosUm campo está ausente ou é inválido. message indica qual.
400no_valid_inputsclient.reduce.run()Todas as entradas estavam vazias.
400invalid_edlclient.edit.applyEdl()A lista de decisões de edição não passou na validação.
400limit_reachedclient.developerApps.create()Você já tem o número máximo de apps.
400locked_fieldclient.apps.run()Uma substituição tentou alterar um destino, como a URL de um webhook.
409name_takenPersonagens, organizaçõesO nome ou o slug já está em uso.
409concurrent_modificationLocais, objetosO item mudou desde que você o leu.
410voice_cloning_retiredclient.voices.createClone()A clonagem de voz não é mais oferecida. Use o design de voz para criar uma voz.
503provider_unavailableclient.llm.structuredJob()A instância não consegue executar este modelo. Não tente de novo.
503feature_disabledclient.copilotO recurso está desativado nesta implantação.
503nodaro_connection_requiredclient.edit.editPlan()Uma instalação self-hosted precisa de uma conexão com o Nodaro Cloud para isso.

Cada página de referência lista os códigos dos próprios métodos. A página Erros da API REST lista todos os códigos que a API pode enviar.

Tentar de novo com segurança

  • Repita leituras à vontade. Um get ou um list não tem efeitos colaterais.
  • Não repita às cegas uma requisição paga. Uma requisição que excedeu o tempo limite pode ter iniciado uma execução mesmo assim. Antes de repetir uma geração, passe uma chave de idempotência: client.nodes.run(type, params, { idempotencyKey }) e runAndWait aceitam uma. Reutilize a mesma chave ao repetir a mesma requisição, e a plataforma retorna a primeira execução em vez de iniciar e cobrar uma segunda.
  • Studio e Recast usam tokens de nova tentativa próprios: clientRequestId nos métodos do Studio e requestId em client.recast.rescore().
  • Repita respostas 5xx com uma pausa. Um fetch personalizado em createClient é um bom lugar para essa lógica.

throwFromResponse(status, body)

throwFromResponse(status: number, body: {
  error?: { code?: string; message?: string; [key: string]: unknown }
}): never

Converte um status HTTP e um corpo de erro do Nodaro na classe de erro correspondente e a lança. O SDK usa essa função em todas as respostas, e ela é exportada para transportes personalizados que chamam a API sem o cliente.

Prop

Type

import { throwFromResponse } from "@nodaro/sdk"

throwFromResponse(403, {
  error: { code: "insufficient_scope", message: "Missing scope", missingScope: "workflows:execute" },
})
// throws a ForbiddenError whose missingScope is "workflows:execute"

Perguntas frequentes

Última atualização

Nesta página