facebook/relay · error

LiveResolverCache: `ServerWeak` normalization info must not

Error message

LiveResolverCache: `ServerWeak` normalization info must not be normalized; it is read in place off the transplanted record.

What it means

In LiveResolverCache's normalization switch, the 'ServerWeak' case is unreachable by design: ServerWeak values are read in place from a transplanted record and are short-circuited by _setResolverValue before normalization. Reaching this throw indicates an internal invariant was violated, not a user error.

Source

Thrown at packages/relay-runtime/store/live-resolvers/LiveResolverCache.js:877

        // inner model instance: the model's field resolvers are wired via
        // `resolverDataInjector(..., '__relay_model_instance', ...)`, which reads
        // `MODEL_PROPERTY_NAME` and passes it to the resolver as the model — so
        // storing the wrapper would make every field resolve to `undefined`.
        const record = RelayModernRecord.create(outputTypeDataID, typename);

        const modelValue =
          MODEL_PROPERTY_NAME in value ? value[MODEL_PROPERTY_NAME] : value;
        RelayModernRecord.setValue(record, MODEL_PROPERTY_NAME, modelValue);

        source.set(outputTypeDataID, record);
        return source;
      }
      case 'ServerWeak': {
        // A read-in-place shadow server-value arm is never normalized:
        // `_setResolverValue` short-circuits before reaching here, because the
        // value is already normalized once by the magic-fragment transplant.
        // Reaching this case would mean that guard was bypassed.
        throw new Error(
          'LiveResolverCache: `ServerWeak` normalization info must not be ' +
            'normalized; it is read in place off the transplanted record.',
        );
      }
      default:
        normalizationInfo.kind as empty;
        invariant(
          false,
          'LiveResolverCache: Unexpected normalization info kind `%s`.',
          normalizationInfo.kind,
        );
    }
  }

  // If a given record does not exist, creates an empty record consisting of
  // just an `id` field, along with a namespaced `__id` field and insert it into
  // the store.
  ensureClientRecord(id: string, typeName: string): DataID {

View on GitHub (pinned to 668b1b85e0)

Solutions

  1. Align all relay-related package versions (react-relay, relay-runtime, relay-test-utils) to the same release
  2. Remove custom subclasses/patches around LiveResolverCache and use the public API
  3. Report with a reproduction to facebook/relay if it occurs on a single consistent version — this is an internal invariant failure
  4. As a workaround, disable experimental live resolvers to avoid the code path

Example fix

// before
"relay-runtime": "13.2.0",
"react-relay": "14.1.0" // mismatched internals
// after
"relay-runtime": "14.1.0",
"react-relay": "14.1.0"
Defensive patterns

Strategy: try-catch

Validate before calling

null

Type guard

null

Try / catch

try {
  readViaLiveResolverCache();
} catch (e) {
  if (String(e.message).includes('ServerWeak')) {
    console.error('Internal LiveResolverCache invariant violated; check relay package version alignment');
  } else throw e;
}

Prevention

When it happens

Trigger: An internal bug or version mismatch bypassing the _setResolverValue short-circuit so a ServerWeak resolver value reaches getNormalized resolver code — e.g. mixing relay-runtime versions of live-resolver internals, or custom cache subclasses routing values through normalization directly.

Common situations: Mismatched relay/react-relay package versions where LiveResolverCache internals disagree; monkey-patching or subclassing LiveResolverCache; a genuine Relay bug after upgrading.

Related errors


AI-assisted analysis of facebook/relay@668b1b85e0 (2026-09-02). Data as JSON: /api/errors/7c405bc217b74eed. Report an issue: GitHub.