Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

The data property of a Boom error gets mangled when the error comes from a validator

Abierto
#4,582 3 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

  • #4584 de @cyphercodes — cerrado sin fusionar

Evaluación

Dificultad
3/5
Tiempo estimado
1-2 días
Aptitud para principiantes
70/100
Tipo de issue
Error
Claridad
Bastante claro
Estado de actividad
Activo
Stack tecnológico
javascript, node.js
Área
api, backend

Línea de trabajo

Comienza con la reproducción de example.mjs, especialmente con el esquema validate.query de la ruta y la ruta del error de Joi, y compárala después con el caso del handler y el formatter onPreResponse. Sigue cómo el error del validador se convierte en la respuesta y confirma que el objeto de datos esperado se conserva; la segunda aserción de la reproducción debería pasar.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

bug
Runtime

node.js

Runtime version

v24.12.0

Module version

v21.4.9

Last module version without issue

v20.3.0

Used with

hapi application

Any other relevant information

I believe https://github.com/hapijs/hapi/pull/4350 introduced an edge case issue.

What are you trying to achieve or the steps to reproduce?

Here is a distilled test to showcase the issue.

import Boom from "@hapi/boom"; // 10.0.1
import Hapi from "@hapi/hapi"; // 21.4.9
import Joi from "joi"; // 18.2.3

import assert from "node:assert";
import { afterEach, beforeEach, describe, it } from "node:test";

describe("error mangling showcase", () => {
  let server;
  const myError = Boom.badRequest("My message", { my: "data" });

  beforeEach(async () => {
    // Initialize Hapi
    server = Hapi.server();
    await server.initialize();

    // Set up a basic global error response formatter to expose the error's data property
    server.ext("onPreResponse", (request, h) => {
      const { response } = request;

      if (response.isBoom) {
        const error = response;
        error.output.payload = {
          error: {
            message: error.message,
            data: error.data,
          },
        };
      }

      return h.continue;
    });
  });

  afterEach(async () => {
    await server.stop();
  });

  it("throws myError from handler", async () => {
    server.route({
      method: "GET",
      path: "/",
      handler: function () {
        throw myError;
      },
    });

    const res = await server.inject({
      method: "get",
      url: "/",
    });

    // This assertion passes regarless of Hapi version
    assert.deepStrictEqual(res.result, {
      error: {
        message: "My message",
        data: { my: "data" },
      },
    });
  });

  it("throws myError from validation schema", async () => {
    server.route({
      method: "GET",
      path: "/",
      handler: function () {
        return "Hello world!";
      },
      options: {
        validate: {
          query: Joi.object({
            dummy: Joi.required().error(myError),
          }),
        },
      },
    });

    const res = await server.inject({
      method: "get",
      url: "/",
    });

    // This assertion fails on Hapi v21 and onward
    assert.deepStrictEqual(res.result, {
      error: {
        message: "My message",
        // the data is { defaultError: myError } starting from Hapi v21
        data: { my: "data" },
      },
    });
  });
});
What was the result you got?
$ node --test example.mjs 
▶ issue showcase
  ✔ throws myError from handler (23.230669ms)
  ✖ throws myError from validation schema (11.012993ms)
✖ issue showcase (35.352659ms)
ℹ tests 2
ℹ suites 1
ℹ pass 1
ℹ fail 1
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 399.773655

✖ failing tests:

test at example.mjs:62:3
✖ throws myError from validation schema (11.012993ms)
  AssertionError [ERR_ASSERTION]: Expected values to be strictly deep-equal:
  + actual - expected
  
  + <ref *2> {
  - {
      error: {
  +     data: <ref *1> {
  +       defaultError: Error: My message
  +           at SuiteContext.<anonymous> (file:///[redacted]/example.mjs:10:24)
  +           at Suite.runInAsyncScope (node:async_hooks:214:14)
  +           at Suite.createBuild (node:internal/test_runner/test:1478:13)
  +           at new Suite (node:internal/test_runner/test:1469:28)
  +           at Test.createSubtest (node:internal/test_runner/test:865:18)
  +           at run (node:internal/test_runner/harness:364:28)
  +           at test (node:internal/test_runner/harness:378:12)
  +           at file:///[redacted]/example.mjs:8:1
  +           at ModuleJob.run (node:internal/modules/esm/module_job:413:25)
  +           at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:660:26) {
  +         data: [Circular *1],
  +         isBoom: true,
  +         isServer: false,
  +         output: {
  +           headers: {},
  +           payload: [Circular *2],
  +           statusCode: 400
  +         }
  +       }
  -     data: {
  -       my: 'data'
        },
        message: 'My message'
      }
    }
  
      at TestContext.<anonymous> (file:///[redacted]/example.mjs:83:12)
      at process.processTicksAndRejections (node:internal/process/task_queues:103:5)
      at async Test.run (node:internal/test_runner/test:1113:7)
      at async Suite.processPendingSubtests (node:internal/test_runner/test:788:7) {
    generatedMessage: true,
    code: 'ERR_ASSERTION',
    actual: { error: { message: 'My message', data: [Object] } },
    expected: { error: { message: 'My message', data: [Object] } },
    operator: 'deepStrictEqual',
    diff: 'simple'
  }
What result did you expect?
$ node --test example.mjs
▶ issue showcase
  ✔ throws myError from handler (35.244367ms)
  ✔ throws myError from validation schema (12.917042ms)
✔ issue showcase (50.673704ms)
ℹ tests 2
ℹ suites 1
ℹ pass 2
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 718.821985
Lenguaje dominante
JavaScript
Estrellas
14.8k
Forks
1.4k
Merge medio
17 min
PR fusionados (30 d)
4

Preparar el entorno

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de hapijs/hapi

Todos los issues de hapijs/hapi

Issues similares

Más issues de JavaScript

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.