Skip to content

Feed core — error handling

The core throws exactly one error type, GhostwritrError, for every failure — config, network, HTTP, and contract violations. It’s always catchable and inspectable. For the cross-SDK model, see error handling.

class GhostwritrError extends Error {
readonly status: number; // HTTP status, or 0 for client-side/config/network
readonly code: GhostwritrErrorCode | null;
readonly details?: unknown; // the offending URL or raw payload, for debugging
}

instanceof GhostwritrError works across transpile targets. Branch on code, not on the message.

catch and branch
import { fetchArticles, GhostwritrError } from "@ghostwritr/feed";
try {
const articles = await fetchArticles({ siteId });
} catch (err) {
if (err instanceof GhostwritrError && err.code === "NOT_FOUND") {
// This site has no feed yet — render an empty state.
} else {
throw err; // unexpected — let it surface
}
}

GhostwritrErrorCode:

codewhenstatus
CONFIGbad input — missing siteId/slug, invalid staticBaseUrl0
NETWORK_ERRORthe underlying fetch rejected (offline, DNS, TLS)0
NOT_FOUNDthe feed manifest is absent — the site has no feed404
INVALID_RESPONSEthe feed returned non-JSON or a malformed manifest/article/timestamp0 or HTTP
UNAUTHORIZEDHTTP 401 from the origin401
FORBIDDENHTTP 403 from the origin403
RATE_LIMITEDHTTP 429 from the origin429
SERVER_ERRORHTTP 5xx (or an unmapped status) from the origin≥500

The type is ... | (string & {}), so the union stays open to future codes — handle a default branch.

Reads fail closed: there is no API key and no authed fallback, so a read either succeeds against the static feed or throws. The two contract codes to know:

  • NOT_FOUND — the manifest is missing, so the site has no feed. This is the “un-backfilled site” signal. fetchArticles throws it; it does not return []. (An empty but present feed returns []. A missing article from fetchArticle returns null. Only a missing feed throws.)
  • INVALID_RESPONSE — the feed responded, but the bytes violate the contract: non-JSON, a malformed manifest, an article missing a guaranteed field, or an unparseable timestamp. A published article is a complete article, so this is never silently coerced.
  • The concept — the cross-SDK error contract. See Error handling.
  • Inject resilience — the opts.fetch seam. See Fetchers.
  • Full surface — every export, typed. See API reference.