Ir al contenido

Errores de la librería

Antes de que un comprobante llegue al SRI hay tres momentos donde puede fallar: al generar (datos inválidos), al firmar (problemas con el .p12 o el XML) y al enviar (el SRI lo rechaza). Cada uno lanza un tipo de error distinto y todos se pueden distinguir con instanceof.

generateXmlInvoice(...) valida el comprobante completo antes de construir el XML. Si algo no cuadra lanza una ValidationException que reúne todos los fallos de una vez, no solo el primero.

validacion.ts
import { generateXmlInvoice, ValidationException } from "osodreamer-sri-xml-signer";
try {
const { generatedXml } = await generateXmlInvoice(comprobante);
} catch (error) {
if (error instanceof ValidationException) {
// error.errors es un string[] con cada problema encontrado
error.errors.forEach((e) => console.error(e));
}
}

Un ejemplo de lo que trae errors:

Valor inválido para "infoFactura.totalConImpuestos.totalImpuesto[0].codigo".
Recibido: "2" (string). Permitidos: 2 (number), 3 (number), 5 (number).
El campo adicional "RUC Proveedor" (0999999999001) no coincide con "rucProveedor"
(1719369561001). Envie solo uno de los dos.

signXml(...) lanza el error original enriquecido con un code, así que puedes usar tanto instanceof como el código.

firma.ts
import {
signXml,
InvalidP12PasswordError,
InvalidP12StructureError,
type SignXmlError,
} from "osodreamer-sri-xml-signer";
try {
const firmado = await signXml({ p12Buffer, password, xmlBuffer });
} catch (error) {
if (error instanceof InvalidP12PasswordError) {
// pedir de nuevo la contraseña al usuario
} else if (error instanceof InvalidP12StructureError) {
// el archivo subido no es un .p12
} else {
console.error((error as SignXmlError).code);
}
}
error.code Clase Qué significa
P12_STRUCTURE_ERROR InvalidP12StructureError El archivo no es un PKCS#12 (.p12) válido. Suele ser un archivo equivocado o corrupto
P12_PASSWORD_ERROR InvalidP12PasswordError El .p12 es válido, pero la contraseña es incorrecta
XML_STRUCTURE_ERROR InvalidXmlStructureError El XML que se intenta firmar no es válido
UNKNOWN_SIGN_STRATEGY UnknownSignStrategyError La entidad que emitió el certificado no está soportada. Ver Certificado .p12
SIGNING_KEY_NOT_FOUND SigningKeyNotFoundError No se encontró la clave de firma dentro del certificado
PRIVATE_KEY_EXTRACTION_ERROR PrivateKeyExtractionError No se pudo extraer la clave privada del archivo
UANATACA_CERT_NOT_FOUND UanatacaCertificateNotFoundError No se encontró el certificado dentro de un .p12 de Uanataca
SIGN_STRATEGY_ERROR SignStrategyError Fallo genérico al aplicar la estrategia de firma
INFRASTRUCTURE_ERROR InfrastructureError Fallo de infraestructura no clasificado
UNHANDLED_ERROR Un Error que la librería no reconoce
UNKNOWN_ERROR Se lanzó algo que ni siquiera es un Error

Las clases están jerarquizadas: SigningKeyNotFoundError, PrivateKeyExtractionError y UanatacaCertificateNotFoundError extienden SignStrategyError, que a su vez extiende InfrastructureError. Puedes capturar por la rama que te interese.

Al validar o autorizar, un rechazo del SRI llega como excepción con todos los datos de la respuesta.

envio.ts
import { validateXml, SRIRejectedError } from "osodreamer-sri-xml-signer";
try {
await validateXml({ xml, env: "test" });
} catch (error) {
if (error instanceof SRIRejectedError) {
error.identificador; // el código: "43", "39", "52"...
error.mensajeSRI; // el mensaje del SRI
error.informacionAdicional; // el detalle del caso concreto
error.tipo; // ERROR o ADVERTENCIA
error.estado; // DEVUELTA, NO AUTORIZADO...
error.claveAcceso;
}
}

SRIAutorizacionError se lanza en el paso de autorización y añade ambiente y comprobanteXml. SRIUnauthorizedError cubre el caso de un estado no autorizado sin mensajes asociados.

Qué significa cada identificador está en Errores del SRI.

Capturar de lo más específico a lo más general, en el orden del flujo:

manejo-completo.ts
import {
ValidationException,
InvalidP12PasswordError,
SRIRejectedError,
type SignXmlError,
} from "osodreamer-sri-xml-signer";
try {
const { generatedXml } = await generateXmlInvoice(comprobante);
const firmado = await signXml({ p12Buffer, password, xmlBuffer: encode(generatedXml) });
await validateXml({ xml: encode(firmado), env: "prod" });
} catch (error) {
if (error instanceof ValidationException) {
return { ok: false, motivo: "datos", detalles: error.errors };
}
if (error instanceof InvalidP12PasswordError) {
return { ok: false, motivo: "certificado" };
}
if (error instanceof SRIRejectedError) {
return { ok: false, motivo: "sri", codigo: error.identificador };
}
throw error; // lo que no reconoces, no lo silencies
}