danny-avila/LibreChat · error · AgentRunEnvelopeError

${path} contains symbol keys

Error message

${path} contains symbol keys

What it means

Thrown by cloneJsonValue when an object or array in the payload has one or more own symbol-keyed properties (Object.getOwnPropertySymbols returns a non-empty list). JSON only has string keys, so symbol-keyed properties are silently dropped by JSON.stringify; the envelope clone rejects them outright to make the loss explicit. This catches hidden 'tag' symbols that libraries attach to mark objects (e.g. React $$typeof, mongoose symbols).

Source

Thrown at packages/api/src/agents/envelope.ts:131

      throw new AgentRunEnvelopeError(`${path} must contain only finite numbers`);
    }
    return value;
  }

  if (typeof value !== 'object') {
    throw new AgentRunEnvelopeError(`${path} contains a non-JSON ${typeof value} value`);
  }

  if (ancestors.has(value)) {
    throw new AgentRunEnvelopeError(`${path} contains a circular reference`);
  }

  ancestors.add(value);

  try {
    const symbolKeys = Object.getOwnPropertySymbols(value);
    if (symbolKeys.length > 0) {
      throw new AgentRunEnvelopeError(`${path} contains symbol keys`);
    }

    if (Array.isArray(value)) {
      const cloned: unknown[] = new Array(value.length);
      let clonedItemCount = 0;
      for (const key of Object.getOwnPropertyNames(value)) {
        if (key === 'length') {
          continue;
        }
        const index = Number(key);
        if (
          !Number.isSafeInteger(index) ||
          index < 0 ||
          index >= value.length ||
          String(index) !== key
        ) {
          throw new AgentRunEnvelopeError(`${path} contains non-index array properties`);
        }

View on GitHub (pinned to 5ff282f900)

Solutions

  1. Map the object to a plain literal with only the fields you need (pick/serialize) before placing it in the payload.
  2. Call Object.getOwnPropertySymbols(obj).forEach(s => delete obj[s]) if you intentionally want to strip them (only when safe).
  3. Construct payload objects from explicit field lists rather than spreading SDK/ORM return values.

Example fix

// before
const doc = await Model.findById(id).lean(); // may carry mongoose symbols
createAgentRunEnvelope({ protocol, requestId, receivedAt, principal, payload: { record: doc } });

// after
const doc = await Model.findById(id).lean();
const record = JSON.parse(JSON.stringify(doc)); // or explicit pick
createAgentRunEnvelope({ protocol, requestId, receivedAt, principal, payload: { record } });
Defensive patterns

Strategy: type-guard

Validate before calling

function hasSymbolKeys(value: unknown): boolean {
  return typeof value === 'object' && value !== null && Object.getOwnPropertySymbols(value).length > 0;
}
function stripSymbolsDeep(obj: unknown): unknown {
  if (Array.isArray(obj)) return obj.map(stripSymbolsDeep);
  if (obj && typeof obj === 'object') {
    const clean: Record<string, unknown> = {};
    for (const [k, v] of Object.entries(obj)) clean[k] = stripSymbolsDeep(v);
    return clean;
  }
  return obj;
}

Type guard

function isSymbolFree(value: unknown, seen = new WeakSet()): boolean {
  if (typeof value !== 'object' || value === null) return true;
  if (seen.has(value as object)) return true; // cycle handled elsewhere
  seen.add(value as object);
  if (Object.getOwnPropertySymbols(value).length > 0) return false;
  const vals = Array.isArray(value) ? value : Object.values(value);
  return vals.every((v) => isSymbolFree(v, seen));
}

Try / catch

try {
  const env = createAgentRunEnvelope(input);
} catch (e) {
  if (e instanceof AgentRunEnvelopeError && /symbol keys/.test(e.message)) {
    input.payload = JSON.parse(JSON.stringify(input.payload)) as typeof input.payload;
    // retry — JSON round-trip drops symbol keys
  } else throw e;
}

Prevention

When it happens

Trigger: Passing a Mongoose document, a React element, a styled-components object, or any value that has been processed by a library that tags objects with Symbol() keys. Also a manually set obj[Symbol('flag')] = true.

Common situations: Passing a raw ORM/document object straight into the envelope instead of a plain DTO; spreading a library-annotated object into the payload; using a Symbol as a private field convention.

Related errors


AI-assisted analysis of danny-avila/LibreChat@5ff282f900 (2026-08-12). Data as JSON: /api/errors/6fffd767cf0f3574. Report an issue: GitHub.