{"record":{"id":"eb8482049b12d8e2","repo":"github/copilot-sdk","slug":"unsupported-object","errorCode":"unsupported_object","errorMessage":"${context.label} contains a non-JSON array property at ${path}","messagePattern":"(.+?) contains a non-JSON array property at (.+?)","errorType":"validation","errorClass":"ResponseError","httpStatus":null,"severity":"error","filePath":"nodejs/src/session.ts","lineNumber":2373,"sourceCode":"                path\n            );\n        }\n\n        ancestors.add(current);\n        try {\n            if (Array.isArray(current)) {\n                const keys = Reflect.ownKeys(current);\n                if (\n                    keys.length !== current.length + 1 ||\n                    keys.some(\n                        (key) =>\n                            key !== \"length\" &&\n                            (typeof key !== \"string\" ||\n                                !/^(0|[1-9]\\d*)$/.test(key) ||\n                                Number(key) >= current.length)\n                    )\n                ) {\n                    throw strictJsonValidationError(\n                        context,\n                        \"unsupported_object\",\n                        `${context.label} contains a non-JSON array property at ${path}`,\n                        path\n                    );\n                }\n                for (let index = 0; index < current.length; index++) {\n                    const descriptor = Object.getOwnPropertyDescriptor(current, String(index));\n                    if (\n                        descriptor === undefined ||\n                        !descriptor.enumerable ||\n                        !(\"value\" in descriptor)\n                    ) {\n                        throw strictJsonValidationError(\n                            context,\n                            \"unsupported_object\",\n                            `${context.label} contains a non-JSON array property at ${path}[${index}]`,\n                            `${path}[${index}]`","sourceCodeStart":2355,"sourceCodeEnd":2391,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/nodejs/src/session.ts#L2355-L2391","documentation":"Arrays destined for the journal must contain only dense, canonical index properties. If an array has an own property that is not 'length', not a canonical array index string, or an index string whose numeric value is >= the array length (i.e. a non-index property or out-of-range hole), the validator rejects it as a non-JSON array property. This keeps journal data exactly round-trippable through JSON.","triggerScenarios":"Assigning named properties to arrays (arr.foo = 1), creating sparse arrays (arr[10] = 1 with gaps) and then journaling them as factory results/steps, or adding properties beyond arr.length.","commonSituations":"Tagging arrays with metadata (arr.total = n), sparse arrays from `delete arr[i]` or `new Array(n)` with partial fills, third-party APIs returning arrays with extra fields.","solutions":["Inspect the `path` and move the extra property to a wrapper object: { items: [...], total: n }.","Densify sparse arrays before journaling (fill holes with null or use Array.from).","Replace `delete arr[i]` with arr[i] = null to keep the array dense and index-canonical."],"exampleFix":"// before\nconst items = [\"a\", \"b\"];\n(items as any).total = 2;\nreturn { items };\n// after\nreturn { items: [\"a\", \"b\"], total: 2 };","handlingStrategy":"validation","validationCode":"function assertDenseArrays(value, path = \"$\") {\n  if (Array.isArray(value)) {\n    for (const key of Object.keys(value)) {\n      if (key !== \"length\" && !/^(0|[1-9]\\d*)$/.test(key))\n        throw new Error(`Non-index property \"${key}\" on array at ${path}`);\n    }\n    if (value.length !== Object.keys(value).filter(k => k !== \"length\").length)\n      throw new Error(`Sparse or holey array at ${path}`);\n    value.forEach((v, i) => assertDenseArrays(v, `${path}[${i}]`));\n  } else if (value && typeof value === \"object\") {\n    for (const [k, v] of Object.entries(value)) assertDenseArrays(v, `${path}.${k}`);\n  }\n}","typeGuard":"const isDenseArray = (v: unknown): v is unknown[] =>\n  Array.isArray(v) && Object.keys(v).length === v.length;","tryCatchPattern":"try {\n  session.runFactory(step);\n} catch (e) {\n  if (e?.details?.category === \"unsupported_object\" && e.message.includes(\"array property\")) {\n    console.error(`Fix extra/sparse array property at ${e.details.path}`);\n  } else throw e;\n}","preventionTips":["Never attach metadata to arrays; wrap in an object instead.","Use arr[i] = null instead of delete arr[i]; avoid new Array(n) with partial fills.","Sanitize third-party arrays (strip extra fields) before journaling."],"tags":["json","validation","arrays","factory-result"],"backgroundTag":"json-serialization-failed","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}