Skip to content

Keep the class and cause of cached key fetch failures in KvKeyCache #1168

Description

@dahlia

Background

fetchKeyDetailed() stores why fetching a key failed in the key cache, so that verifyRequestDetailed() can report the same keyFetchError for later requests without fetching the key again. When the failure has no HTTP response, KvKeyCache.setFetchError() stores only the error's name and message (packages/fedify/src/federation/keycache.ts), and KvKeyCache.getFetchError() rebuilds it as a plain Error with that name.

So a cached failure is not the same as the one it was made from:

  • it is no longer an instance of FetchError (or of any other class), so error instanceof FetchError fails;
  • its cause is gone;
  • FetchError.url is gone.

This matters more since #1131, which makes the built-in document loaders throw a FetchError without a response on a timeout, and documents error.cause being a DOMException named "TimeoutError" as the way to tell a timeout apart. The first request whose key fetch times out gets that error, but every request within the unavailable key TTL (10 minutes by default) gets a plain Error whose only trace of the timeout is its message, …: Timed out after 10000 ms. The Timeouts section of docs/manual/context.md notes this as a limitation. The same applies to other failures without a response, such as DNS failures (UrlError with its reason) and disallowed private addresses.

Proposed work

Keep enough of a failure without a response in KvKeyCache to rebuild what applications check, e.g.:

  • the class for known errors (FetchError, UrlError), with FetchError.url and UrlError.reason;
  • the name and message of the cause, rebuilt as a DOMException when it was one.

Entries stored by earlier versions have only errorName and errorMessage, so reading them must keep working, and a new entry should still be readable by an older version during a rolling upgrade (e.g., by adding fields rather than changing the existing ones). Unknown error classes can fall back to the current behavior.

Tests

  • A key fetch that times out is reported by verifyRequestDetailed() with a FetchError whose cause is named "TimeoutError", both the first time and when read back from a new KvKeyCache over the same KvStore.
  • A DNS failure keeps its UrlError class and reason when cached.
  • An entry in the old format is still read as before.

Activity

  1. junghoon-vans commented on Oct 4, 2026

    @junghoon-vans
    Contributor

    @dahlia Hi! I'd like to work on this issue. Would it be okay for me to take it on?

    I've looked through KvKeyCache and the existing timeout tests. My plan is to preserve the known error types, their relevant fields, and cause information while keeping the cache format compatible with older versions. I'll also extend the regression coverage for cached timeout and DNS failures, and old-format entries.

  2. added this to the Fedify 2.5 milestone on Oct 4, 2026
  3. dahlia commented on Oct 4, 2026

    @dahlia
    MemberAuthor

    @junghoon-vans Sure, thanks!

  4. linked a pull request that will close this issuePreserve cached key fetch failure details #1237on Oct 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Fields

Priority

None yet

Effort

None yet

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions