facebook/react · error · Error
To taint a value, a lifetime must be defined by passing an o
Error message
To taint a value, a lifetime must be defined by passing an object that holds the value.
What it means
React's taintUniqueValue requires a lifetime object — an object or function that holds the secret and stays alive exactly as long as the secret does — so React can forget the taint via weak semantics when the holder is collected. Passing null or a primitive (string, number, boolean) as the lifetime throws because React would either never clean up or track the wrong scope.
Source
Thrown at packages/react/src/ReactTaint.js:70
? new FinalizationRegistry(cleanup)
: null;
export function taintUniqueValue(
message: ?string,
lifetime: Reference,
value: string | bigint | $ArrayBufferView,
): void {
if (!enableTaint) {
throw new Error('Not implemented.');
}
// eslint-disable-next-line react-internal/safe-string-coercion
message = '' + (message || defaultMessage);
if (
// $FlowFixMe[invalid-compare]
lifetime === null ||
(typeof lifetime !== 'object' && typeof lifetime !== 'function')
) {
throw new Error(
'To taint a value, a lifetime must be defined by passing an object that holds ' +
'the value.',
);
}
let entryValue: string | bigint;
if (typeof value === 'string' || typeof value === 'bigint') {
// Use as is.
entryValue = value;
} else if (
value instanceof TypedArrayConstructor ||
value instanceof DataView
) {
// For now, we just convert binary data to a string so that we can just use the native
// hashing in the Map implementation. It doesn't really matter what form the string
// take as long as it's the same when we look it up.
// We're not too worried about collisions since this should be a high entropy value.
TaintRegistryByteLengths.add(value.byteLength);
entryValue = binaryToComparableString(value);View on GitHub (pinned to eafeac097b)
Solutions
- Pass the object that holds the secret (e.g. the per-request cache/session object) as the lifetime: taintUniqueValue(message, requestContext, token)
- If no natural holder exists, create one (const lifetime = {token}) and keep it alive as long as the secret
- Ensure the lifetime is neither null nor a primitive; functions are also accepted as holders
Example fix
// before taintUniqueValue(msg, 'session-token', token); // string lifetime -> throws // after const session = await loadSession(); taintUniqueValue(msg, session, session.token); // object lifetime
Defensive patterns
Strategy: validation
Validate before calling
// Validate the lifetime argument before tainting
function isLifetime(v: unknown): v is object | Function {
return v !== null && (typeof v === 'object' || typeof v === 'function');
}
if (isLifetime(lifetime)) {
taintUniqueValue(message, lifetime, secret);
} else {
throw new TypeError('lifetime must be the object holding the secret');
} Type guard
const isTaintLifetime = (v: unknown): v is object | Function => v != null && (typeof v === 'object' || typeof v === 'function');
Prevention
- Always pass the request/session object that owns the secret as the lifetime
- Wrap taint calls in a small helper that validates (lifetime, value) types once and fails with a clear message
When it happens
Trigger: taintUniqueValue(message, 'user', secret) or taintUniqueValue(message, null, secret) — passing a primitive or null where the API expects the object that contains the value (e.g. the request or user session object).
Common situations: Calling the server-security taint APIs for the first time and misunderstanding the second parameter as a label/scope string; refactoring code that previously passed a symbol or string as the lifetime.
Related errors
- taintUniqueValue cannot taint objects or functions. Try tain
- Cannot taint a ${kind} because the value is too general and
- Only objects or functions can be passed to taintObjectRefere
- Only objects or functions can be passed to taintObjectRefere
- getProfilingData not supported by this renderer
AI-assisted analysis of facebook/react@eafeac097b (2026-08-21).
Data as JSON: /api/errors/57130d7404c63d8a.
Report an issue: GitHub.