{"record":{"id":"4fd953d53929b8ee","repo":"facebook/relay","slug":"relay-resolver-error-at-path-fielderror-fieldp","errorCode":null,"errorMessage":"Relay: Resolver error at path '${fieldError.fieldPath}' in '${fieldError.owner}'. Message: ${fieldError.error.message}","messagePattern":"Relay: Resolver error at path '(.+?)' in '(.+?)'\\. Message: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/relay-runtime/util/handlePotentialSnapshotErrors.js","lineNumber":48,"sourceCode":"    // site's error handling infrastructure.\n\n    // Awkward. We don't want to attach the ui context in RelayReader where we\n    // create the event, but it means we need to add it here instead of just\n    // passing the event through.\n\n    environment.relayFieldLogger({\n      // the uiContext on fieldError undefined *always*,\n      ...fieldError,\n      // and this is where we assign loggingContext to uiContext to populate it\n      uiContext: loggingContext,\n    });\n  }\n\n  for (const fieldError of fieldErrors) {\n    if (eventShouldThrow(fieldError)) {\n      switch (fieldError.kind) {\n        case 'relay_resolver.error':\n          throw new Error(\n            `Relay: Resolver error at path '${fieldError.fieldPath}' in '${fieldError.owner}'. Message: ${fieldError.error.message}`,\n          );\n        case 'relay_field_payload.error':\n          throw new Error(\n            `Relay: Received a field error in the server response for field '${fieldError.fieldPath}' in '${fieldError.owner}'. Message: ${fieldError.error.message}`,\n          );\n        case 'missing_expected_data.throw':\n          throw new Error(\n            `Relay: Missing expected data at path '${fieldError.fieldPath}' in '${fieldError.owner}'. See https://relay.dev/docs/next/debugging/why-null/ for likely causes.`,\n          );\n        case 'missing_required_field.throw': {\n          let reason: string;\n          if (fieldError.fieldValue === null) {\n            reason =\n              fieldError.fieldError != null\n                ? `the server returned null with an error: ${fieldError.fieldError.message}`\n                : 'the server returned null';\n          } else {","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/facebook/relay/blob/668b1b85e06261aa3b58dabfc51f8b5524a70955/packages/relay-runtime/util/handlePotentialSnapshotErrors.js#L30-L66","documentation":"handlePotentialSnapshotErrors converts field-level error events recorded during a store lookup into thrown errors. When a 'relay_resolver.error' event is marked to throw (eventShouldThrow), it throws an Error embedding the resolver field path, owner operation, and the underlying error message, surfacing resolver failures to the caller of the snapshot read.","triggerScenarios":"Reading a snapshot (e.g. via environment.lookup or useLazyLoadQuery render) where a Live Resolver threw during evaluation, and the error's disposition is 'throw' rather than log.","commonSituations":"A Resolver function throws or rejects during query/render; @throwOnFieldError directive present; tests asserting on resolver errors; missing required data inside a resolver causing it to raise.","solutions":["Inspect fieldPath/owner in the message to locate the failing resolver and fix its logic (null checks, expected data)","Wrap the resolver's data access with @required or handle missing data so it degrades instead of throwing","Catch the error at the query boundary (ErrorBoundary / try-catch around lookup) and render an error UI","If the error should be logged not thrown, change disposition (remove @throwOnFieldError or configure relayFieldLogger handling)"],"exampleFix":"// before\n// resolver throws on missing actor\nconst name = actor.name;\n// after\nconst name = actor?.name ?? 'unknown';","handlingStrategy":"try-catch","validationCode":"null","typeGuard":"null","tryCatchPattern":"try {\n  const snapshot = environment.lookup(fragment);\n  handlePotentialSnapshotErrors(env, snapshot.fieldErrors, snapshot.missingClientEdges);\n  return snapshot;\n} catch (e) {\n  if (String(e.message).startsWith('Relay: Resolver error at path')) {\n    renderResolverErrorUI(e);\n    return null;\n  }\n  throw e;\n}","preventionTips":["Null-guard optional data inside Resolver functions","Use @required semantics instead of raw dereferences on possibly-missing fields","Wrap query reads in ErrorBoundary components","Point resolver authors at fieldPath/owner in the message for fast debugging"],"tags":["relay","resolver","field-error","snapshot"],"backgroundTag":"resolver-field-error","analyzedSha":"668b1b85e06261aa3b58dabfc51f8b5524a70955","analyzedAt":"2026-09-02T19:57:20.783Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}