---
title: Catálogo de errores
description: Referencia de los códigos que emite la API, con next_action accionable por código y request_id para correlacionar con soporte.
url: https://notta.cl/docs/errors
related:
  - https://notta.cl/docs/rate-limits
  - https://notta.cl/docs/api/dtes
  - https://notta.cl/docs/nota-credito-61
  - https://notta.cl/docs/webhooks
---

> Documentación de Notta en markdown. Índice completo: https://notta.cl/llms.txt — corpus entero: https://notta.cl/llms-full.txt

# Catálogo de errores

Todos los errores Notta siguen el shape `{ code, message, request_id, hint?, next_action?, detail?, docs_url? }`. El campo `next_action` es enumerable y está diseñado para que un agente LLM pueda razonar qué hacer sin necesidad de leer el `message`.

## Estructura

```ts
type ErrorResponse = {
  code: string;          // "nc.over_cedida.blocked"
  message: string;       // human-readable
  request_id: string;    // siempre presente — UUID por request
  hint?: string;         // fix sugerido
  next_action?: string;  // enum estable: "confirm_override_and_retry" | "retry_with_backoff" | ...
  detail?: Record<string, unknown>; // campos públicos del error, p. ej. { "retryAfterSec": 30 }
  docs_url?: string;     // link a la doc del error, cuando aplica
  issues?: unknown[];    // solo en validation_failed — issues Zod con path + message por campo
};
```

Incluye el `request_id` al contactar soporte: es el identificador que correlaciona tu request con los logs del servidor.

## Códigos por dominio

Cuando un código no trae `next_action` (marcado con —), la corrección sale del `code` más el `detail`.

### Autenticación y permisos

| Código | HTTP | Descripción | `next_action` |
|---|---|---|---|
| `unauthorized` | 401 | Falta el header `Authorization: Bearer` | `send_bearer_token` |
| `invalid_api_key` | 401 | La API key no matchea ninguna key activa | `regenerate_api_key` |
| `api_key_expired` | 401 | API key expirada | `regenerate_api_key` |
| `api_key_revoked` | 401 | API key revocada | `regenerate_api_key` |
| `forbidden` | 403 | La key no tiene el scope requerido (`dte:read` / `dte:write`) | `use_api_key_with_required_scope` |
| `cert_id_missing` | 400 | Falta el header `X-Cert-Id` en un verbo que firma | `send_cert_id_header` |
| `cert_id_ambiguous` | 400 | La org tiene varios certificados vigentes — especifica cuál firma con `X-Cert-Id` | `send_cert_id_header` |
| `org.required` | 412 | La sesión de dashboard no tiene organización — completa el onboarding de org (aplica a `/certificates`, `/caf` y `/api-keys`) | — |
| `org.rut_missing` | 412 | La organización de la sesión no tiene RUT registrado — complétalo en el onboarding antes de sincronizar el RCV | — |
| `onboarding_production_not_authorized` | 403 | La org todavía no está habilitada para emitir en producción (palena) | — |
| `csrf_origin_mismatch` | 403 | `Origin` no permitido para esta acción (protección CSRF de la sesión de dashboard; no aplica al camino `Authorization: Bearer`) | — |

### Validación del payload

| Código | HTTP | Descripción | `next_action` |
|---|---|---|---|
| `validation_failed` | 400 | El body no pasa el schema — revisa `issues[]` campo por campo | `fix_body_and_retry` |
| `invalid_json` | 400 | El body no es JSON válido | `fix_json_body_and_retry` |
| `idempotency_key_missing` | 400 | Falta el header `Idempotency-Key` (obligatorio en todo POST de emisión) | `send_idempotency_key_header` |
| `receptor_rut_invalid` | 400 | RUT receptor con DV inválido | — |
| `emisor_rut_mismatch` | 422 | El `rut_emisor` del body no coincide con el RUT del certificado | — |
| `emisor.profile_incompleto` | 422 | Faltan datos del perfil del emisor para emitir (`detail.missing`) | `complete_emisor_profile` |
| `items_empty` | 400 | `items` vacío | — |
| `items_exceed_max` | 400 | `items` supera el máximo (límite SII; `detail.count`) | — |
| `amount_arithmetic` | 400 | Los montos declarados no cuadran aritméticamente | — |
| `references_required` | 400 | El `tipo_dte` exige `references` y no vienen | — |
| `reference_invalid_cod_ref` | 400 | `cod_ref` fuera del enum 1/2/3 | — |
| `text_correction_must_be_zero` | 400 | NC de corrección de texto (`cod_ref` 2) debe llevar montos en cero | — |
| `dte.tipo_not_supported` | 400 | `tipo_dte` no soportado por este pipeline | `fix_tipo_dte_and_retry` |
| `dte.34.invalid_exenta` | 422 | DTE 34 (Factura Exenta) con items afectos | `fix_tipo_dte_and_retry` |
| `dte.41.afecto_not_allowed` | 422 | Boleta Exenta 41 con items afectos | `fix_tipo_dte_and_retry` |
| `dte.46.invalid_afecta` | 422 | DTE 46 (Factura de Compra) con items exentos — es una operación 100% afecta (cambio de sujeto) | `remove_exento_items_and_retry` |
| `dte.mixed_retencion_references` | 422 | Una NC/ND mezcla una referencia con retención total de IVA (Factura de Compra 46) y otra sin retención — no hay un total coherente para todo el documento | `split_into_separate_documents_by_retencion` |
| `dte.type.prod_not_certified` | 422 | El tipo de DTE aún no está certificado para producción (gate N1 por tipo); emítelo en certificación (maullin) mientras se completa la cert ante el SII | `emit_dte_in_cert` |
| `idempotency_conflict` | 409 | Mismo `Idempotency-Key` con otro body — `detail.existingDteId` apunta al DTE original | — |

### Lectura y estado del DTE

| Código | HTTP | Descripción | `next_action` |
|---|---|---|---|
| `not_found` | 404 | El recurso no existe o pertenece a otra org (DTEs y boletas) | — |
| `dte.xml.not_yet_available` | 404 | El DTE todavía no tiene XML — el workflow de firma sigue corriendo | `poll_self` |
| `dte.pdf.not_signed` | 409 | El DTE existe pero no está firmado — el PDF requiere el TED (síguelo en `xml_url`) | `poll_self` |
| `dte.refresh_status.no_track_id` | 409 | El DTE aún no fue subido al SII — no hay `track_id` que consultar | `wait_for_emit_workflow` |
| `dte.refresh_status.no_cert` | 409 | La org no tiene certificado activo para autenticar la consulta de estado | — |
| `dte.resend_delivery.not_wired` | 501 | El reenvío del DTE al receptor no está disponible en este entorno | — |
| `dte.resend_delivery.tipo_not_supported` | 422 | El `tipo_dte` no se envía al receptor (las boletas 39/41 van a consumidores por el pipeline REST) | — |
| `dte.resend_delivery.no_email` | 422 | El DTE no tiene correo del receptor — incluye `correo_receptor` en el body para reenviar | `provide_correo_receptor` |

### Muestras impresas (certificación)

| Código | HTTP | Descripción | `next_action` |
|---|---|---|---|
| `dte.muestras.empty` | 422 | No hay DTEs firmados (33/34/56/61) para armar el lote de muestras | `emit_and_sign_dtes_first` |
| `dte.muestras.no_samples` | 422 | No hay DTEs firmados para enviar como muestras al SII | `emit_and_sign_dtes_first` |
| `dte.muestras.too_large` | 422 | El lote supera el límite de 3 MB del SII | `paginate_into_multiple_emails` |
| `dte.muestras.send_not_configured` | 422 | El remitente de email no está configurado en el servidor | `contact_support` |
| `dte.muestras.not_sent` | 422 | El envío no salió por una razón no mapeada — `message` trae el motivo | — |
| `dte.muestras.send_not_wired` | 501 | El envío de muestras no está disponible en este entorno | — |

### Certificado y folios (CAF) en la emisión

| Código | HTTP | Descripción | `next_action` |
|---|---|---|---|
| `cert_not_found` | 404 | No hay certificado digital cargado para la org | — |
| `cert_expired` | 422 | Certificado expirado (`detail.expiredAt`) | — |
| `cert_subject_mismatch` | 422 | El RUT del certificado no corresponde al emisor | — |
| `cert.kms.auth_failed` | 422 | Falló el descifrado del certificado (`detail.phase`) — rotación de KEK o seed inconsistente | `reseed_certificate` |
| `caf_not_found` | 404 | No hay CAF cargado para ese tipo de DTE (`detail.tipoDte`) | — |
| `caf_expired` | 422 | CAF vencido (`detail.expiredAt`) | — |
| `caf_exhausted` | 422 | CAF sin folios disponibles | — |
| `sii_env_mismatch` | 422 | El CAF corresponde a otro ambiente SII (certificación vs producción) que el del DTE | — |
| `dte.production_resolucion_missing` | 409 | Falta la Resolución Exenta del SII (NroResol/FchResol) para emitir a producción — se ingiere del email del SII a la casilla del emisor | `capture_sii_resolucion` |
| `dte.46.prod_not_certified` | 422 | DTE 46 (Factura de Compra) habilitado solo en certificación (maullin) — la certificación oficial del tipo 46 para producción está en curso | `emit_dte_46_in_cert` |

### Gestión de certificados (`/certificates`)

| Código | HTTP | Descripción | `next_action` |
|---|---|---|---|
| `cert.invalid_request` | 400 | Falta `file`, `password` o `label` en el form-data | — |
| `cert.invalid` | 422 | No se pudo leer el `.p12` (corrupto, sin llave privada, o clave equivocada) | — |
| `cert.duplicate` | 409 | Ese certificado (misma huella SHA-256) ya está cargado para la org | — |
| `cert.not_found` | 404 | El certificado no existe para la org | — |
| `cert.expired` | 409 | El certificado está vencido; no puede quedar como predeterminado | — |

### Gestión de CAF (`/caf`)

| Código | HTTP | Descripción | `next_action` |
|---|---|---|---|
| `caf.invalid_request` | 400 | Falta `file` en el form-data | — |
| `caf.parse_error` | 422 | El XML del CAF no trae los campos requeridos (RE/TD/D/H) | — |
| `caf.wrong_tipo` | 422 | El CAF subido no corresponde al `tipo_esperado` del recuadro | — |
| `caf.no_certificate` | 422 | No hay certificado cargado — sube el certificado antes del CAF | — |
| `caf.duplicate` | 409 | Ese rango de folios ya está registrado | — |
| `caf.not_found` | 404 | El CAF no existe para la org | — |
| `caf.has_accepted_dtes` | 409 | No se puede eliminar: tiene DTEs aceptados por el SII (retención legal de 6 años) | — |
| `caf.has_ceded_dtes` | 409 | No se puede eliminar: un DTE del CAF fue cedido vía RPETC | — |
| `caf.request_in_flight` | 409 | Ya hay una solicitud reciente de folios para este tipo — espera unos minutos antes de reintentar | — |
| `caf.request_failed` | 502 | La solicitud de folios al SII falló — `message` trae el motivo | — |
| `caf.grant_rejected` | 502 | El SII no concedió el folio (rechazo del timbraje) — `message`/`data` traen el detalle | — |
| `caf.cert_not_authorized` | 502 | El certificado activo no está autorizado a solicitar folios (timbrar) para esta empresa en el SII — revisa los usuarios autorizados en Mi SII o cambia el certificado activo | — |
| `caf.type_not_prod_certified` | 409 | Este tipo de documento aún no está certificado para producción. Completa la certificación por-tipo antes de solicitar folios. | — |

### Notas de crédito y débito (compliance)

| Código | HTTP | Descripción | `next_action` |
|---|---|---|---|
| `dte.nota_credito.fuera_plazo` | 422 | NC fuera del plazo legal de 6 meses (Ley 21.398) | `consult_lawyer_or_use_correction_path` |
| `nc.over_cedida.blocked` | 422 | Factura referenciada cedida vía RPETC con aceptación irrevocable ≥8 días (Corte Suprema 2025) | `confirm_override_and_retry` |
| `dte.nota_credito.cedida_override_required` | 409 | Mismo bloqueo de cesión, detectado por el chequeo de emisión: requiere override explícito | `confirm_override_and_retry` |
| `dte.nota_credito.invalid_cod_ref` | 422 | `cod_ref` inválido para NC — usa 1 (anula), 2 (corrige texto), 3 (corrige montos) | `fix_cod_ref_and_retry` |
| `dte.nota_credito.reference_tipo_unsupported` | 422 | NC 61 solo referencia facturas 33 o 34 | `use_factura_33_or_34_reference` |
| `dte.nota_debito.interese_moratorio_legal` | 422 | Intereses moratorios legales no se documentan con DTE (Oficio SII 2011/2020) | `consult_oficio_2011_2020` |
| `dte.nota_debito.invalid_reason` | 422 | `nd_reason` fuera del enum válido (`detail.validReasons`) | `fix_reason_and_retry` |

### Guía de despacho (52)

| Código | HTTP | Descripción | `next_action` |
|---|---|---|---|
| `dte.52.dispatch_required` | 400 | DTE 52 requiere el bloque `despacho` | `include_despacho_and_retry` |
| `dte.52.invalid_traslado` | 422 | `ind_traslado` fuera de los valores soportados (`detail.supported`) | `fix_ind_traslado_and_retry` |
| `dte.52.transportista_required` | 422 | Falta el transportista (`detail.field`) — Res. 154/2025 | — |
| `dte.52.conductor_required` | 422 | Falta el conductor (`detail.field`) — Res. 154/2025 | — |
| `dte.52.vehiculo_required` | 422 | Falta el vehículo (`detail.field`) — Res. 154/2025 | — |
| `dte.52.parent_invalid` | 500 | Inconsistencia interna con el documento padre referenciado | — |

### SII y errores transitorios

| Código | HTTP | Descripción | `next_action` |
|---|---|---|---|
| `sii_rejection` | 422 | El SII rechazó el DTE — `detail.code` y `detail.glosa` traen el veredicto | — |
| `sii_unavailable` | 503 | SII caído transitorio (`detail.retryAfterSec`) | — |
| `sii_invalid_track_id` | 502 | El SII no reconoce el track id del envío | — |
| `rate_limit` | 429 | Límite de tasa superado (`detail.retryAfterSec`) — ver [Límites de tasa](/docs/rate-limits) | — |
| `internal_error` | 500 | Error no mapeado; el detalle queda en los logs del servidor | — |

### Boletas

| Código | HTTP | Descripción | `next_action` |
|---|---|---|---|
| `boleta.credentials.not_found` | 404 | Falta la clave tributaria SII de la org | `configure_sii_credentials` |
| `boleta.rest.unavailable` | 502 | Endpoint REST de boletas del SII no disponible (`detail.retryAfterSec`) | `retry_with_backoff` |
| `boleta.rest.token_expired` | 401 | Token del pipeline REST expirado | `reauthenticate` |
| `boleta.rest.pipeline_error` | 500 | El pipeline REST falló en una fase interna (`detail.phase`) | `operator_review` |
| `boleta.xml.not_yet_available` | 404 | La boleta todavía no tiene XML — el pipeline sigue corriendo | `poll_self` |
| `validation_error` | 422 | El payload del batch de boletas no pasa el schema — revisa `errors[]` | — |
| `boleta.batch.exceeds_max` | 422 | El batch supera el máximo (`detail.max`) | `split_batch` |
| `boleta.batch.idempotency_conflict` | 409 | Posición del batch ya ocupada (`detail.batchId`) | `poll_existing_or_change_key` |
| `boleta.batch.not_found` | 404 | El `batchId` no existe para la org | `verify_batch_id` |

### BHE

| Código | HTTP | Descripción | `next_action` |
|---|---|---|---|
| `bhe.credential.invalid` | 401 | Clave tributaria BHE no encontrada o rechazada (`detail.reason`) | `configure_bhe_credential` |
| `bhe.plazo_anulacion.expired` | 422 | BHE fuera del plazo de 3 meses para anular | `consult_sii_or_manual_rectification` |
| `bhe.retencion.mismatch` | 422 | La retención enviada no concuerda con la tasa legal del año (`detail.expected`) | `use_calculated_retencion` |
| `bhe.receptor.tipo_invalid` | 422 | Tipo de receptor inválido para BHE | `fix_receptor_and_retry` |
| `bhe.rest.unavailable` | 502 | Endpoint BHE del SII (`loa.sii.cl`) no disponible (`detail.retryAfterSec`) | `retry_with_backoff` |
| `bhe.rest.token_expired` | 401 | Token del pipeline BHE expirado | `reauthenticate` |
| `bhe.rest.pipeline_error` | 500 | El pipeline BHE falló en una fase interna (`detail.phase`) | `operator_review` |
| `bhe.not_found` | 404 | La BHE no existe para la org | — |

### Billing

| Código | HTTP | Descripción | `next_action` |
|---|---|---|---|
| `billing.free_tier_exceeded` | 402 | Cuota mensual del plan alcanzada (`detail.usedThisMonth` / `detail.limit`) — suscribite a un plan superior o espera al próximo período | `upgrade_plan` |

### Infraestructura (transitorios del servidor)

Reintenta con backoff; si persisten, contacta soporte con el `request_id`.

| Código | HTTP | Descripción | `next_action` |
|---|---|---|---|
| `db.unavailable` | 503 | La base de datos no está disponible | — |
| `db.pool_exhausted` | 503 | El pool de conexiones a la base de datos está saturado — reintenta | — |
| `cert.kms_unavailable` | 503 | El KMS que cifra certificados no está disponible | — |
| `caf.kms_unavailable` | 503 | El KMS que cifra CAFs no está disponible | — |
| `cert.insert_failed` | 500 | Falló la persistencia del certificado | — |
| `caf.insert_failed` | 500 | Falló la persistencia del CAF | — |

### RCV y RCOF

| Código | HTTP | Descripción | `next_action` |
|---|---|---|---|
| `rcv.sync.failed` | 502 | El sync del RCV falló contra el SII (`detail.periodo`) | `retry_sync` |
| `rcv.unauthorized` | 401 | Clave tributaria rechazada por el SII para RCV | `configure_sii_credential` |
| `rcv.period.invalid` | 422 | Periodo inválido — debe ser `YYYY-MM` y no estar en el futuro (`detail.reason`) | `fix_period_and_retry` |
| `rcof.no_data` | 422 | Sin boletas 39/41 emitidas en esa fecha — no se genera RCOF (`detail.fecha`) | `verify_fecha` |
| `rcof.aggregation_error` | 500 | Falló la agregación de boletas del día para el RCOF | — |
| `rcof.build_error` | 500 | Falló la construcción del XML del RCOF | — |
| `rcof.upload_error` | 502 | El envío del RCOF al SII falló (`detail.phase`) | `retry_resend` |

## Ejemplo: factura cedida

```json
{
  "code": "nc.over_cedida.blocked",
  "message": "NC inoponible al cesionario: la factura referenciada (folio 1234) tiene una cesión RPETC aceptada irrevocablemente (Doctrina Corte Suprema 2025).",
  "hint": "Factura cedida via RPETC con cesión irrevocable (≥8d). Set override_cedida=true en el body con respaldo operacional firmado.",
  "next_action": "confirm_override_and_retry",
  "detail": { "folioRef": 1234 },
  "request_id": "9f3b2c61-7d4a-4e0b-9c2d-1a5e8f3b7c90"
}
```

## Rechazos del SII (al subir el DTE)

Cuando el SII recibe el `EnvioDTE` corre una cascada de validadores: XSD → schema → firma → carátula → timbre. Cada validador enmascara al siguiente, así que corregir un rechazo suele destapar el próximo en ese mismo orden.

El `getEstUp` del SII devuelve solo el código de cabecera (`RFR`/`RCT`/`EPR`); el **sub-código accionable** (p. ej. `CRT-3-19`, `TED-2-510`) llega por email del SII. Notta lo expone en `sii_glosa`.

| Rechazo | Significado | Acción |
|---|---|---|
| `RFR` | Rechazado por Error en Firma (canonicalización c14n / xmlns heredado / charset de la firma) | Re-firmar el DTE con la canonicalización y el encoding correctos |
| `CHR-00002` | Línea muy larga o encoding latin1 — aflora como `RFR`/`RSC` | Corregir el encoding/largo de línea y re-firmar |
| `RCT` | Rechazado por Error en Carátula | Corregir la Carátula y reenviar |
| `CRT-3-19` | Sub-código de `RCT`: Fecha/Número de Resolución inválido (`FchResol`/`NroResol`) | Corregir la resolución y reenviar |
| `TED-2-510` | Reparo: Firma del Timbre Electrónico (TED/FRMT) incorrecta — el DTE queda en `EPR` con reparo | Re-firmar el timbre sobre el `DD` canónico y reenviar |

### `RFR` — Rechazado por Error en Firma

**La firma se rompió porque los bytes canónicos que el SII verifica no son los que se firmaron: un `xmlns` heredado que el c14n omite al firmar e incluye al verificar, o un XML re-serializado después de firmar.**

Cómo verificarlo: ejecuta un roundtrip local de firma + verificación sobre los bytes exactos que van al wire. Si el elemento firmado (`SetDTE`/`Documento`) solo hereda el namespace sin declararlo, el self-verify falla — redeclara `xmlns` explícito y firma con `c14n-20010315` (el c14n exclusivo lo rechaza el XSD del SII).

### `CHR-00002` — línea muy larga o charset inválido

**El validador de charset cortó el envío porque alguna línea del XML supera los 4090 caracteres o los bytes no van en ISO-8859-1.**

Cómo verificarlo: mide el largo de línea máximo del XML enviado y confirma que el wire va como latin1, con saltos de línea entre las secciones mayores (`Encabezado`, `Detalle`, `TED`).

### `RCT` — Rechazado por Error en Carátula

**La carátula declara datos que el SII no tiene registrados para el emisor: `RutEmisor`/`RutEnvia` que no corresponden, o una resolución (`FchResol`/`NroResol`) inválida.**

Cómo verificarlo: el sub-código del email del SII apunta al campo exacto (p. ej. `CRT-3-19` es la resolución). Compara cada campo de la carátula contra lo registrado para la empresa en el SII antes de reenviar.

### `CRT-3-19` — Fecha/Número de Resolución inválido

**La `FchResol` no es la fecha que el SII tiene registrada para tu empresa: en certificación el comodín `2014-08-22` no sirve para empresas recién postuladas — el SII espera la fecha real de postulación.**

Cómo verificarlo: reenvía con `FchResol` = fecha en que la empresa postuló como emisor electrónico en maullin y `NroResol` = `0` (válido para todo emisor en certificación). Si el envío pasa, el comodín era el problema.

### `TED-2-510` — firma del timbre incorrecta

**La firma `FRMT` se calculó sobre los bytes literales del `DD`, pero el SII la verifica sobre el `DD` canónico con el whitespace entre elementos colapsado.**

Cómo verificarlo: verifica la `FRMT` localmente contra la clave pública del CAF usando `dd.replace(/>\s+</g, "><")` como input. Si verifica con la forma canónica y falla con la literal, re-firma el timbre sobre la canónica (preservando los bytes literales del CAF en el wire).

> **Corrección automática:**
Notta corrige la mayoría de estos rechazos automáticamente; este catálogo te ayuda a entender el `sii_glosa` cuando un DTE queda en un estado de rechazo.

## Cómo manejar errores en código

```ts
const res = await fetch("https://app.notta.cl/api/v1/dtes", { /* ... */ });
if (!res.ok) {
  const err = await res.json();
  switch (err.next_action) {
    case "retry_with_backoff": return retryLater(err.detail?.retryAfterSec);
    case "regenerate_api_key": return notifyOps(err);
    case "confirm_override_and_retry": return promptUser(err);
    default: throw new Error(`${err.code} (request_id: ${err.request_id})`);
  }
}
```

## Buenas prácticas

- Decide por `error.code` (y `next_action` cuando viene), nunca por string-matching del `message`: el texto puede cambiar, los códigos no.
- `next_action` es enumerable y estable — los valores existentes no cambian de semántica; solo se agregan nuevos.
- No reintentes los `4xx` salvo `429`: un `400`/`422` va a fallar igual hasta que corrijas el payload. Los `502`/`503` transitorios sí se reintentan con backoff.
- Loguea el `request_id` de cada error en tu sistema: acelera cualquier diagnóstico con soporte.

## Próximos pasos

- **[Límites de tasa](/docs/rate-limits)** — el detalle del `429` y el patrón de backoff para errores transitorios.
- [Referencia API de DTEs](/docs/api/dtes) — los endpoints que emiten estos códigos.
- [Nota de crédito (61)](/docs/nota-credito-61) — el flujo completo detrás de `nc.over_cedida.blocked` y el plazo de 6 meses.
- [Webhooks](/docs/webhooks) — el contrato de eventos para reaccionar a rechazos sin polling.
