danny-avila/LibreChat · error · AgentRunEnvelopeError

${path} contains non-index array properties

Error message

${path} contains non-index array properties

What it means

Thrown by cloneJsonValue for an Array payload value that has own properties whose keys are not valid array indices: the key must parse to a safe integer >= 0, < array.length, and String(index) must equal the key (so '01', '1.0', '-1', 'foo' all fail). JSON arrays only support integer-indexed elements; extra named props would be silently lost, so the clone surfaces them as an error.

Source

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

    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`);
        }
        const descriptor = Object.getOwnPropertyDescriptor(value, key);
        if (!descriptor || !Object.prototype.hasOwnProperty.call(descriptor, 'value')) {
          throw new AgentRunEnvelopeError(`${path}[${index}] must not be an accessor property`);
        }
        const itemValue: unknown = descriptor.value;
        cloned[index] = cloneJsonValue(itemValue, `${path}[${index}]`, ancestors, depth + 1);
        clonedItemCount++;
      }
      if (clonedItemCount !== value.length) {
        throw new AgentRunEnvelopeError(`${path} contains sparse array entries`);
      }
      return cloned;
    }

    const prototype = Object.getPrototypeOf(value);
    if (prototype !== Object.prototype && prototype !== null) {
      const typeName = value.constructor?.name ?? 'object';

View on GitHub (pinned to 5ff282f900)

Solutions

  1. Move any named properties off the array into a sibling object ({ items: [...], meta: {...} }).
  2. If the named prop is stray metadata, delete it before building the envelope (delete arr.foo).
  3. Reconstruct the array via Array.from or spread ([...arr]) which drops non-index own properties.

Example fix

// before
const items = getItems();
items.total = items.length;
createAgentRunEnvelope({ protocol, requestId, receivedAt, principal, payload: { items } });

// after
const items = getItems();
createAgentRunEnvelope({ protocol, requestId, receivedAt, principal, payload: { items: [...items], total: items.length } });
Defensive patterns

Strategy: validation

Validate before calling

function arrayHasOnlyIndexKeys(arr: unknown[]): boolean {
  for (const key of Object.getOwnPropertyNames(arr)) {
    if (key === 'length') continue;
    const i = Number(key);
    if (!Number.isSafeInteger(i) || i < 0 || i >= arr.length || String(i) !== key) return false;
  }
  return true;
}
if (Array.isArray(payload.items) && !arrayHasOnlyIndexKeys(payload.items)) {
  payload.items = [...payload.items]; // spread drops non-index own props
}

Type guard

function isDenseIndexArray(arr: unknown[]): boolean {
  const names = Object.getOwnPropertyNames(arr).filter((k) => k !== 'length');
  return names.every((k) => {
    const i = Number(k);
    return Number.isSafeInteger(i) && i >= 0 && i < arr.length && String(i) === k;
  });
}

Try / catch

try {
  const env = createAgentRunEnvelope(input);
} catch (e) {
  if (e instanceof AgentRunEnvelopeError && /non-index array properties/.test(e.message)) {
    // reconstruct arrays via [...arr] which keeps only indexed elements
  } else throw e;
}

Prevention

When it happens

Trigger: Attaching a named property to an array (arr.count = 5, arr['meta'] = {...}), a negative or fractional key, or a string key like '01' that round-trips to a different index. Also arr.foo after Object.defineProperty.

Common situations: Using an array as a carrier for both a list and metadata (arr.total = n); libraries that annotate arrays with named fields; copying an array-like collection (arguments, NodeList) that gained extra props.

Related errors


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