facebook/relay · error

fetchQuery: Invalid fetchPolicy ${fetchPolicy}

Error message

fetchQuery: Invalid fetchPolicy ${fetchPolicy}

What it means

fetchQuery validates the fetchPolicy argument against a switch of known policies ('network-only', 'store-or-network', etc.). The default case is reached when the caller passes an unrecognized or misspelled policy, so Relay throws instead of silently falling back to a default.

Source

Thrown at packages/relay-runtime/query/fetchQuery.js:178

        ).map(readData);
      } else {
        observable = getNetworkObservable<$FlowFixMe>(
          environment,
          operation,
        ).map(readData);
      }
      environment.__log({
        name: 'fetchquery.fetch',
        operation,
        fetchPolicy,
        queryAvailability,
        shouldFetch,
      });
      return observable;
    }
    default:
      fetchPolicy as empty;
      throw new Error('fetchQuery: Invalid fetchPolicy ' + fetchPolicy);
  }
}

function getNetworkObservable<TQuery extends OperationType>(
  environment: IEnvironment,
  operation: OperationDescriptor,
): RelayObservable<TQuery['response']> {
  return fetchQueryInternal
    .fetchQuery(environment, operation)
    .map(() => environment.lookup(operation.fragment));
}

module.exports = fetchQuery;

View on GitHub (pinned to 668b1b85e0)

Solutions

  1. Use one of the supported policies: 'store-only' | 'store-or-network' | 'store-and-network' | 'network-only'
  2. Import the FetchPolicy type from relay-runtime and annotate the option so typos are caught at compile time
  3. If porting from Apollo, map the old policy to the closest Relay equivalent (e.g. network-first -> store-or-network with network-only for forced refresh)
  4. Check the installed relay version's fetchQuery.js switch to confirm the policy still exists

Example fix

// before
fetchQuery(env, query, vars, {fetchPolicy: 'cache-first'});
// after
fetchQuery(env, query, vars, {fetchPolicy: 'store-or-network'});
Defensive patterns

Strategy: validation

Validate before calling

const VALID = ['store-only','store-or-network','store-and-network','network-only'];
if (fetchPolicy != null && !VALID.includes(fetchPolicy)) throw new TypeError(`Invalid fetchPolicy: ${fetchPolicy}`);
fetchQuery(env, query, vars, {fetchPolicy});

Type guard

const isFetchPolicy = (p) => ['store-only','store-or-network','store-and-network','network-only'].includes(p);

Try / catch

try {
  fetchQuery(env, q, vars, {fetchPolicy});
} catch (e) {
  if (String(e.message).startsWith('fetchQuery: Invalid fetchPolicy')) {
    console.error('Bad fetchPolicy, falling back to store-or-network');
  } else throw e;
}

Prevention

When it happens

Trigger: Calling environment.fetchQuery(query, variables, {fetchPolicy: '...'}) or environment.executeWithFetchPolicy with a policy string other than store-only, store-or-network, store-and-network, or network-only — e.g. a typo like 'network_first' or a policy copied from a different library like 'cache-first'.

Common situations: Copy-pasting Apollo Client fetch policies (cache-first, network-first) into Relay code; hand-rolled string variables typed loosely; version drift where an experimental policy was removed or renamed.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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