Skip to main content

error-reporting

Error handling and logging policy for @shopify/hydrogen: when to throw, when to log through the logging contract, when to expose reactive state, and how tests assert failures. Always use when developing or reviewing runtime logic for the @shopify/hydrogen library.

Quellinformationen

Repository
Shopify/hydrogen
Letzte Quellaktivität
28. September 2026 um 11:19
Erkannte Sprache von SKILL.md
Englisch
Sterne
2.163
Forks
454

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
error-reporting
description
Error handling and logging policy for @shopify/hydrogen: when to throw, when to log through the logging contract, when to expose reactive state, and how tests assert failures. Always use when developing or reviewing runtime logic for the @shopify/hydrogen library.
# Error Reporting Policy How `@shopify/hydrogen` handles runtime failures: when to throw, when to log, when to expose reactive state, and how logs are formatted, configured, and tested. Apply this policy to any new or changed runtime logic in `packages/hydrogen/src`. ## Taxonomy Pick the mechanism from the failure class. Never double-report (throw AND log the same failure). | Failure class | Mechanism | Examples | | --- | --- | --- | | Programming errors | Throw a typed error synchronously. | Bad arguments, invariant violations. | | Request-scoped failures with a caller | Throw a typed error; the caller decides retry/render. | `StorefrontApiError`, `CustomerAccountApiError`, `CartActionError`, `CartNetworkError`. | | Server handlers with internal recovery | Catch failures, log via the scoped logger, return a structured error `Response`. | Cart server handler catches a network failure and returns `500` with a JSON error body. | | Background browser failures | Scoped logger at `error` level. | Runtime script loads, background cart loads, analytics publish failures. | | Misuse / degradation | Scoped logger at `warn` level. | Mock shop detected, analytics destination misconfigured, deprecated option passed. | | Buyer-visible user errors | Reactive state only — never logged. | Cart `userErrors` surfaced to the UI; the user corrects and retries. | ## Logger contract ### Internal call convention `getLogger` is internal — not part of the public package API. ```ts import { getLogger } from "../logging"; // relative import within src/ const log = getLogger("cart"); log.error("cart initial load failed", { error }); ``` - `getLogger(scope)` returns a lazily-resolved scoped logger. Prefer one module-level `const log` per file when the scope is static. Use stable subsystem scopes; proxy descriptors provide dynamic scopes. - Messages are unprefixed, lowercase-leaning, and without trailing colons; the sink owns formatting. - `context.error` becomes a separate console argument; other context keys become a trailing object. - Never call `console.*` directly in runtime files under `packages/hydrogen/src` — the `no-console` lint rule enforces this. Sanctioned runtime exceptions: the built-in sink in `src/core/logging/logging.ts`, the serialized consent bootstrap in `src/core/shopify-scripts/consent-script.ts`, and the CLI. Tests may spy on or mock `console` for the exceptions listed below. ### `HydrogenLogger` A minimal structural interface with six level methods: ```ts interface HydrogenLogger { trace: (message: string, context?: LogContext) => void; debug: (message: string, context?: LogContext) => void; info: (message: string, context?: LogContext) => void; warn: (message: string, context?: LogContext) => void; error: (message: string, context?: LogContext) => void; fatal: (message: string, context?: LogContext) => void; } ``` `LogContext` is `{ scope?: string; error?: unknown; [key: string]: unknown }`. ### `configureLogging` ```ts import { configureLogging } from "@shopify/hydrogen"; const logger = { trace: console.debug, debug: console.debug, info: console.info, warn: console.warn, error: console.error, fatal: console.error, }; configureLogging({ logger, level: "warn" }); ``` - Global, called once at startup (app entry on the browser, module init on the server). - `logger` — any `HydrogenLogger`; defaults to the built-in console sink. - `level` — minimum severity forwarded; defaults to `"info"`. - Last-call-wins: reconfiguring applies the new options. ### Default console sink Formats entries as `[hydrogen:<level>:<scope>] <message>`, followed by `context.error` (if present) and a trailing object of remaining context fields. ## Serialized inline scripts — documented exception Inline/CDN scripts that Hydrogen serializes into HTML are compiled to strings via `import … with { type: "script" }` chains. They never see the app bundle's global state, so `configureLogging` cannot reach them. The analytics bootstrap path and its bus/destination-manager modules write to `console` with the standard `[hydrogen:<level>:<scope>]` prefix via the `consoleLogger` sink — when writing code in a serialized-script import chain that shares modules with the app bundle, use `consoleLogger` directly with an explicit `{ scope }` instead of `getLogger`. Serialized-only leaf modules (the consent bootstrap) hardcode the prefix in a plain `console.*` call instead, so the logging module is not inlined into every HTML response. ## Non-goals - Per-request child loggers / request correlation. Scopes are per-subsystem, not per-request. ## Test expectations - Failure paths inject a test logger instead of mocking `console`: `configureLogging({ logger })` with six `vi.fn()` methods, `configureLogging({})` in `afterEach` to restore the defaults. Assert `(message, { scope, ...context })` — no prefix strings. - Exceptions that still spy `console`: serialized inline-script import chains (analytics bus/destination-manager, consent) write to `console` directly, and `logging.test.ts` verifies the sink's own `[hydrogen:<level>:<scope>]` formatting. - The `no-console` lint rule enforces the policy: the sanctioned `console` call sites are `src/core/logging/logging.ts` and the serialized consent bootstrap `src/core/shopify-scripts/consent-script.ts`, each carrying an inline `oxlint-disable-next-line no-console`. CLI and test files are exempt.
Auf GitHub ansehen