Skip to content

Error handling

Every failure in @ghostwritr/next throws a single typed error, GhostwritrError. It carries a status (HTTP status, or 0 for client-side/config/network failures), a stable code, the message, and optional details. Reads fail closed: there’s no silent empty result — a missing feed throws.

For the cross-SDK error model, see Error handling.

Import GhostwritrError from the root @ghostwritr/next (it’s client-safe — types and the error class only):

import { GhostwritrError } from "@ghostwritr/next";
import { gw } from "@/lib/ghostwritr";
try {
const articles = await gw.getArticles();
// ...render
} catch (e) {
if (e instanceof GhostwritrError) {
if (e.code === "NOT_FOUND") {
// No published feed for this siteId yet, or the siteId is wrong.
} else {
// Transient: RATE_LIMITED, SERVER_ERROR, NETWORK_ERROR, INVALID_RESPONSE.
}
}
throw e;
}
codestatusWhat it meansWhat to do
NOT_FOUND404No published feed exists for this siteId — an unseeded site, or a wrong/typo’d siteId.Check your siteId. Until you publish your first article, expect this.
RATE_LIMITED429Too many requests to the feed origin.Back off and retry; widen your revalidate window to fetch less often.
SERVER_ERROR5xxThe feed origin returned a server error.Transient — retry, or serve a cached/last-known state.
NETWORK_ERROR0The fetch itself failed (DNS, TLS, connection).Transient — retry. Check connectivity from your runtime.
INVALID_RESPONSEvariesThe feed returned non-JSON, or a malformed manifest/page/article (a contract violation).Not your fault to fix at runtime — log details and report it.
CONFIG0Bad config caught at client creation — missing siteId, or invalid revalidate/tags.Fix the createGhostwritr / createRevalidateHandler call.

NOT_FOUND is the expected state before you publish your first article — the feed doesn’t exist until the engine builds it. Treat it differently from the transient codes: a NOT_FOUND won’t fix itself by retrying, but a RATE_LIMITED, SERVER_ERROR, or NETWORK_ERROR will.

const TRANSIENT = new Set(["RATE_LIMITED", "SERVER_ERROR", "NETWORK_ERROR"]);
try {
return await gw.getArticles();
} catch (e) {
if (e instanceof GhostwritrError && TRANSIENT.has(e.code ?? "")) {
return []; // degrade gracefully; the page renders without the list
}
throw e; // NOT_FOUND / INVALID_RESPONSE / CONFIG are real bugs — surface them
}