← tests

errors

A router miss, a handler's miss, a method the route does not have, and a parser failure.

Comparable across every framework, on the status and on whether the answer carries a body at all. Not on the body's shape, which is the framework's own contract.

{draw.item} is a row of items.large, picked per request. A refusal's status is written 4XX. Frameworks refuse with different statuses, so each declares its own in its client-exception, and the test reads it from there.

testheftrequestbasewhat differs from the base
errors.malformed2POST /body/validate/smallbody.rejected_alla body that is not JSON at all
errors.not_found1GET /items/999999items.readthe request refused rather than served
errors.unmatched1GET /errors/unmatched
errors.wrong_method1POST /items/{draw.item}errors.unmatcheda path the router knows, asked with a method it does not accept, instead of a path it does not know

errors.malformed

heft 2

base body.rejected_all

A body that is not JSON at all. Read against body.rejected_all, the difference is the parser failing rather than the validator refusing, which is often not even the same status inside one framework.

Request

POST /body/validate/small
content-typeapplication/json
{"customerId": 1, "lines": [

Expected response

HTTP 4XX

The status the framework declares as malformed in its client-exception.

The framework's own error body, which is not checked.

Test source, tests/errors/malformed.ts
tests/errors/malformed.tsopen on GitHub →
import { performanceTest } from "#kit";

const path = "/body/validate/small";

/** Truncated mid-array, so the parser fails before any field is ever looked at. */
const MALFORMED = '{"customerId": 1, "lines": [';

export default performanceTest({
  id: { family: "errors", name: "malformed" },
  path,
  base: "body.rejected_all",
  varies: "parse_failure",
  heft: 2,
  about:
    "A body that is not JSON at all. Read against body.rejected_all, the " +
    "difference is the parser failing rather than the validator refusing, " +
    "which is often not even the same status inside one framework.",

  request: (c) => c.post(path).raw(MALFORMED).unparseable(),
});

errors.not_found

heft 1

base items.read

A lookup the router matches and the handler refuses, because no row has that id. Read against items.read, the difference is the refusal in place of a row, and against errors.unmatched it is the handler deciding rather than the router missing.

Request

GET /items/999999

No body.

Expected response

HTTP 4XX

The status the framework declares as notFound in its client-exception.

The framework's own error body, which is not checked.

Test source, tests/errors/not-found.ts
tests/errors/not-found.tsopen on GitHub →
import { performanceTest } from "#kit";

const path = "/items/999999";

export default performanceTest({
  id: { family: "errors", name: "not_found" },
  path,
  base: "items.read",
  varies: "outcome",
  heft: 1,
  about:
    "A lookup the router matches and the handler refuses, because no row has " +
    "that id. Read against items.read, the difference is the refusal in place " +
    "of a row, and against errors.unmatched it is the handler deciding rather " +
    "than the router missing.",

  request: (c) => c.get(path).notFound(),
});

errors.unmatched

heft 1

base of errors.wrong_method

A path no route matches, which is the router's own miss rather than a handler's decision. A framework that walks its whole route table before giving up pays for it here and nowhere else.

Request

GET /errors/unmatched

No body.

Expected response

HTTP 4XX

The status the framework declares as notFound in its client-exception.

The framework's own error body, which is not checked.

Test source, tests/errors/unmatched.ts
tests/errors/unmatched.tsopen on GitHub →
import { performanceTest } from "#kit";

const path = "/errors/unmatched";

export default performanceTest({
  id: { family: "errors", name: "unmatched" },
  path,
  heft: 1,
  about:
    "A path no route matches, which is the router's own miss rather than a " +
    "handler's decision. A framework that walks its whole route table before " +
    "giving up pays for it here and nowhere else.",

  request: (c) => c.get(path).notFound(),
});

errors.wrong_method

heft 1

base errors.unmatched

A path with routes, asked with a method none of them has. A router that matches the path first answers 405, and one that matches the method and the path together answers 404, so the status is read from the framework's declaration. Read against errors.unmatched, the difference is how far the router got before it gave up.

Request

POST /items/{draw.item}

No body.

Expected response

HTTP 4XX

The status the framework declares as wrongMethod in its client-exception.

The framework's own error body, which is not checked.

Test source, tests/errors/wrong-method.ts
tests/errors/wrong-method.tsopen on GitHub →
import { performanceTest } from "#kit";

const path = "/items/{draw.item}";

export default performanceTest({
  id: { family: "errors", name: "wrong_method" },
  path,
  base: "errors.unmatched",
  varies: "known_path",
  heft: 1,
  about:
    "A path with routes, asked with a method none of them has. A router that " +
    "matches the path first answers 405, and one that matches the method and " +
    "the path together answers 404, so the status is read from the " +
    "framework's declaration. Read against errors.unmatched, the difference " +
    "is how far the router got before it gave up.",

  request: (c) => c.post(`/items/${c.draw.item()}`).wrongMethod(),
});