Errores

Todos los códigos de error del contrato de entrega con su estado, su significado y la reacción correcta, incluida la ausencia de salida que nunca inicia una compilación y las respuestas de nivel de servicio.

  • Disponibilidad: Experimental
  • Evidencia: Leído del código fuente
  • Referencia

Un solo sobre

Todo fallo tiene un código estable y un estado HTTP, y viaja como el mismo cuerpo JSON sea cual sea el servicio que lo produce:

JSON
{
  "error": {
    "code": "MODULE_NOT_FOUND",
    "message": "…",
    "diagnostics": [{ "code": "…", "message": "…" }]
  }
}

diagnostics está presente solo cuando hay alguno, lo que hoy significa una compilación fallida. Decide según code. El message es texto técnico en inglés para diagnosticar problemas y puede cambiar.

Una página de otro origen puede leer el error de una solicitud pública, como cualquier respuesta pública: lleva Access-Control-Allow-Origin: *, así que un navegador que no pudo cargar un módulo deja que la página lea el código y el mensaje. Los errores nunca se almacenan (no-store).

JavaScripterrors.mjs
// Every failure is the same JSON envelope on every service. Branch on `code`,
// never on the message.
const origin = process.env.CDN_ORIGIN ?? process.env.DEV_ORIGIN;

// The options of the contract default to published delivery, so a development service refuses them with
// OPTION_UNSUPPORTED before it looks at the identity. A development consumer always asks for its output.
const development = !process.env.CDN_ORIGIN;
const options = development ? 'target=node&format=esm&env=development&min=false&sourcemap=inline' : 'target=browser&format=esm';

// A well-formed identity that no service holds
const request = `/m/@example/does-not-exist@0.0.1/modules/main?${options}`;

const response = await fetch(new URL(request, origin));
const type = response.headers.get('content-type') ?? '';

if (response.ok || !type.includes('application/json')) {
	console.log(`unexpected answer: ${response.status} ${type}`);
	process.exit(1);
}

const { error } = await response.json();
console.log(`${response.status} ${error.code}`);
console.log(error.message);
for (const diagnostic of error.diagnostics ?? []) console.log(`  ${diagnostic.code}: ${diagnostic.message}`);

if (error.code !== 'PACKAGE_NOT_FOUND') process.exitCode = 1;

Códigos

Estado Código Significado Qué hacer
400 IDENTITY_INVALID La ruta no sigue la gramática: una versión que no es exacta, una barra codificada, un segmento de punto, una ruta de recurso incorrecta Corrige la URL. Construye las rutas con el códec compartido.
400 OPTION_INVALID Una opción es desconocida, está repetida, falta siendo obligatoria o tiene un valor fuera de su lista. Una solicitud de recurso estático con cualquier consulta. Corrige la consulta. Consulta Opciones de la solicitud.
400 OPTION_UNSUPPORTED La solicitud es válida y este servicio no puede producir esa salida en absoluto Solicita una salida que el servicio produzca
401 ACCESS_REQUIRED El recurso no es público y la solicitud no lleva contexto de acceso Consulta Acceso privado
403 ACCESS_DENIED El contexto de acceso no permite el recurso Obtén un permiso válido o consulta a un administrador de la aplicación
404 PACKAGE_NOT_FOUND Aquí no se ha preparado nada de este paquete. No dice nada sobre el paquete en su registro. Revisa el nombre y el prefijo del registro, o prepara un release que lo use
404 VERSION_MISMATCH Aquí se preparó otra versión del paquete, no esta Solicita la versión que se sirve, o prepara un release con esta
404 MODULE_NOT_FOUND Esta versión del paquete está disponible aquí y no publica ningún módulo con esta subruta Revisa la subruta. Los archivos internos no son módulos públicos.
404 OUTPUT_NOT_AVAILABLE La identidad es conocida y el servicio no tiene la salida solicitada: un conjunto de opciones que no se preparó, un módulo sin el recurso complementario pedido o un recurso que el paquete no declara Prepara un release que la incluya. Reintentar no cambia nada.
422 BUILD_FAILED Solo en desarrollo. El módulo existe y sus fuentes actuales no producen un artefacto válido. Se incluyen los diagnósticos del compilador y no se sirve en su lugar ninguna salida anterior. Corrige las fuentes
501 SOURCE_UNSUPPORTED El servicio no entrega esta fuente de módulos. Un servidor de desarrollo lo responde para /m/git/…, /m/digest/… y para un paquete instalado desde Git o desde un archivo comprimido. Carga ese paquete desde un origen que entregue su fuente, como un release del CDN que lo fijó
404 NOT_FOUND Nivel de servicio: la ruta no corresponde a nada que este servicio sirva, como otra ruta, un host sin aplicación, o /resolution.json en el origen de entrega compartido Revisa el origen base y la ruta
503 UNAVAILABLE Nivel de servicio: el servicio no puede responder ahora, por ejemplo porque su almacenamiento no responde Reintenta más tarde. No dice nada sobre el recurso.
500 INTERNAL Nivel de servicio: un fallo inesperado. Su mensaje no repite el del fallo. Reintenta, e infórmalo si persiste

Los tres últimos son la respuesta que da un servicio, en una ruta del contrato, a un fallo para el que el contrato no tiene código, de modo que un consumidor nunca se encuentra con el vocabulario de una implementación.

Una salida ausente no es una solicitud de compilación

Cada respuesta de este tipo describe lo que este CDN preparó y retuvo, y nada más. Ninguna afirma nada sobre el paquete en su registro, ni promete que volver a pedirlo compile algo, ni describe lo que preparó otro inquilino.

OUTPUT_NOT_AVAILABLE es la respuesta de un servicio que solo entrega. Significa que el servicio buscó, no encontró nada y no hizo nada más:

  • no se inició, reanudó ni encoló ninguna compilación;
  • la respuesta no es OPTION_UNSUPPORTED, porque el servicio podría tener la salida;
  • la respuesta nunca es immutable, porque la salida se puede preparar más adelante.
JavaScriptmiss.mjs
// A published service only retrieves. A valid request for an output that was
// not prepared is a 404 with OUTPUT_NOT_AVAILABLE, and asking again changes
// nothing: no GET starts a build.
const origin = process.env.CDN_ORIGIN;

// Set UNPREPARED_REQUEST to a valid option set that your release did not prepare
const request = process.env.UNPREPARED_REQUEST ?? '/m/@example/shared@1.0.0/modules/text?target=node&format=cjs';

for (const attempt of [1, 2]) {
	const response = await fetch(new URL(request, origin));
	const { error } = await response.json();
	console.log(`attempt ${attempt}: ${response.status} ${error.code}`);
	console.log(`  Cache-Control: ${response.headers.get('cache-control')}`);

	const acceptable = ['OUTPUT_NOT_AVAILABLE', 'OPTION_UNSUPPORTED'].includes(error.code);
	if (!acceptable) process.exitCode = 1;
}

En un servidor de desarrollo la misma situación se maneja de otra manera a propósito: un módulo conocido se compila desde sus fuentes actuales cuando se solicita, y BUILD_FAILED informa las fuentes que no compilan.

Situación Servidor de desarrollo Entrega publicada
Módulo conocido, salida que no se tiene Compila en el momento 404 OUTPUT_NOT_AVAILABLE
Las fuentes no compilan 422 BUILD_FAILED con diagnósticos No aplica: el fallo pertenece al trabajo de preparación, y el release activo no se toca
Opción válida que el servicio nunca produce 400 OPTION_UNSUPPORTED 400 OPTION_UNSUPPORTED

Errores de selección de salida

Elegir mal la salida de un módulo público en el código fuente, por ejemplo importar un módulo que solo es una hoja de estilos sin .css, no es un error de entrega: se detecta cuando se compila o analiza el módulo que importa, y te llega como diagnóstico de esa compilación en un servidor de desarrollo, o como un trabajo de preparación fallido en el CDN. Los diagnósticos son OUTPUT_NOT_FOUND, OUTPUT_AMBIGUOUS y STYLE_BINDING_UNSUPPORTED; consulta Seleccionar una salida.

En código

JavaScript
import { ContractError } from '@beyond-js/artifact-api';

const response = await fetch(url);
if (!response.ok) {
	const error = ContractError.from(response.status, await response.json());
	error.code; // 'OUTPUT_NOT_AVAILABLE'
	error.status; // 404
	error.diagnostics; // compiler diagnostics of a failed build, when present
}

ContractError.from devuelve undefined cuando el cuerpo no es un sobre de error de este contrato, por ejemplo la página de error HTML de un proxy.