{"record":{"id":"4d0252b147531254","repo":"danny-avila/LibreChat","slug":"path-contains-a-non-plain-typename-value","errorCode":null,"errorMessage":"${path} contains a non-plain ${typeName} value","messagePattern":"(.+?) contains a non-plain (.+?) value","errorType":"validation","errorClass":"AgentRunEnvelopeError","httpStatus":null,"severity":"error","filePath":"packages/api/src/agents/envelope.ts","lineNumber":167,"sourceCode":"        }\n        const descriptor = Object.getOwnPropertyDescriptor(value, key);\n        if (!descriptor || !Object.prototype.hasOwnProperty.call(descriptor, 'value')) {\n          throw new AgentRunEnvelopeError(`${path}[${index}] must not be an accessor property`);\n        }\n        const itemValue: unknown = descriptor.value;\n        cloned[index] = cloneJsonValue(itemValue, `${path}[${index}]`, ancestors, depth + 1);\n        clonedItemCount++;\n      }\n      if (clonedItemCount !== value.length) {\n        throw new AgentRunEnvelopeError(`${path} contains sparse array entries`);\n      }\n      return cloned;\n    }\n\n    const prototype = Object.getPrototypeOf(value);\n    if (prototype !== Object.prototype && prototype !== null) {\n      const typeName = value.constructor?.name ?? 'object';\n      throw new AgentRunEnvelopeError(`${path} contains a non-plain ${typeName} value`);\n    }\n\n    const cloned: { [key: string]: unknown } = {};\n    for (const key of Object.getOwnPropertyNames(value)) {\n      const descriptor = Object.getOwnPropertyDescriptor(value, key);\n      if (descriptor?.enumerable !== true) {\n        throw new AgentRunEnvelopeError(`${path}.${key} must be an enumerable property`);\n      }\n      if (!Object.prototype.hasOwnProperty.call(descriptor, 'value')) {\n        throw new AgentRunEnvelopeError(`${path}.${key} must not be an accessor property`);\n      }\n      const propertyValue: unknown = descriptor.value;\n      Object.defineProperty(cloned, key, {\n        configurable: true,\n        enumerable: true,\n        writable: true,\n        value: cloneJsonValue(propertyValue, `${path}.${key}`, ancestors, depth + 1),\n      });","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/danny-avila/LibreChat/blob/5ff282f9006c436e561de1afd39a481bea1ef0d8/packages/api/src/agents/envelope.ts#L149-L185","documentation":"Thrown by cloneJsonValue for an object whose prototype is neither Object.prototype nor null. Only plain objects (object literals, Object.create(null)) are accepted; class instances, Date, Map, Set, Error, RegExp, and typed arrays are rejected. These carry behavior and hidden slots that do not survive JSON, so the envelope requires the caller to flatten them to plain data explicitly.","triggerScenarios":"Passing a Date, Map, Set, Error, RegExp, Uint8Array, URL, or any class instance (new Foo()) inside the payload. Also a plain object whose __proto__ was reassigned to a non-default prototype.","commonSituations":"Dropping an ORM model instance, a Date timestamp, or a URL object into the request payload instead of its primitive form; passing Error objects caught in a handler onward as payload.","solutions":["Convert class instances to plain literals before insertion: date.toISOString(), [...map.entries()], err.message, buf.toString('base64').","Use JSON.parse(JSON.stringify(obj)) to collapse to a plain object when you know the shape is JSON-safe.","Build payload objects as literal {...} or Object.assign({}, instance) of only the data fields."],"exampleFix":"// before\nconst payload = { createdAt: new Date(), tags: new Set(['a','b']) };\ncreateAgentRunEnvelope({ protocol, requestId, receivedAt, principal, payload });\n\n// after\nconst payload = { createdAt: new Date().toISOString(), tags: [...new Set(['a','b'])] };\ncreateAgentRunEnvelope({ protocol, requestId, receivedAt, principal, payload });","handlingStrategy":"type-guard","validationCode":"function isPlainObjectOrArray(value: unknown): boolean {\n  if (value === null || typeof value !== 'object') return true;\n  const proto = Object.getPrototypeOf(value);\n  if (Array.isArray(value)) return Object.getPrototypeOf(value) === Array.prototype;\n  return proto === Object.prototype || proto === null;\n}\nfunction toPlainDeep(value: unknown): unknown {\n  if (Array.isArray(value)) return value.map(toPlainDeep);\n  if (value && typeof value === 'object') {\n    if (value instanceof Date) return value.toISOString();\n    if (value instanceof Map) return toPlainDeep(Object.fromEntries(value));\n    if (value instanceof Set) return toPlainDeep([...value]);\n    const out: Record<string, unknown> = {};\n    for (const [k, v] of Object.entries(value)) out[k] = toPlainDeep(v);\n    return out;\n  }\n  return value;\n}","typeGuard":"function isPlainJsonValue(value: unknown, seen = new WeakSet()): boolean {\n  if (value === null || typeof value !== 'object') return true;\n  if (seen.has(value as object)) return true;\n  seen.add(value as object);\n  const proto = Object.getPrototypeOf(value);\n  if (Array.isArray(value)) return value.every((v) => isPlainJsonValue(v, seen));\n  if (proto !== Object.prototype && proto !== null) return false;\n  return Object.values(value).every((v) => isPlainJsonValue(v, seen));\n}","tryCatchPattern":"try {\n  const env = createAgentRunEnvelope(input);\n} catch (e) {\n  if (e instanceof AgentRunEnvelopeError && /non-plain/.test(e.message)) {\n    input.payload = JSON.parse(JSON.stringify(input.payload)) as typeof input.payload;\n  } else throw e;\n}","preventionTips":["Convert Date/Map/Set/Error/Buffer to primitives (ISO string, entries array, message, base64) before building the payload.","Type payloads as ChatCompletionRunPayload/ResponsesRunPayload and avoid injecting class instances.","Assert isPlainJsonValue(payload) in unit tests for representative payloads."],"tags":["serialization","json","prototype","class-instance","agent-envelope"],"backgroundTag":null,"analyzedSha":"5ff282f9006c436e561de1afd39a481bea1ef0d8","analyzedAt":"2026-08-12T21:38:08.145Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}