github/copilot-sdk · error · ResponseError
unsupported_object
unsupported_object
Error message
${context.label} contains a non-JSON array property at ${path} What it means
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.
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.
Example fix
// before
const items = ["a", "b"];
(items as any).total = 2;
return { items };
// after
return { items: ["a", "b"], total: 2 }; Defensive patterns
Strategy: validation
Validate before calling
function assertDenseArrays(value, path = "$") {
if (Array.isArray(value)) {
for (const key of Object.keys(value)) {
if (key !== "length" && !/^(0|[1-9]\d*)$/.test(key))
throw new Error(`Non-index property "${key}" on array at ${path}`);
}
if (value.length !== Object.keys(value).filter(k => k !== "length").length)
throw new Error(`Sparse or holey array at ${path}`);
value.forEach((v, i) => assertDenseArrays(v, `${path}[${i}]`));
} else if (value && typeof value === "object") {
for (const [k, v] of Object.entries(value)) assertDenseArrays(v, `${path}.${k}`);
}
} Type guard
const isDenseArray = (v: unknown): v is unknown[] => Array.isArray(v) && Object.keys(v).length === v.length;
Try / catch
try {
session.runFactory(step);
} catch (e) {
if (e?.details?.category === "unsupported_object" && e.message.includes("array property")) {
console.error(`Fix extra/sparse array property at ${e.details.path}`);
} else throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "JSON serialization failed", "not JSON serializable", "Failed to serialize": why JSON marshaling errors happen and how to fix them — this error's family across 46 libraries.
Related errors
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/eb8482049b12d8e2.
Report an issue: GitHub.
Appendix: source
Thrown at nodejs/src/session.ts:2373
path
);
}
ancestors.add(current);
try {
if (Array.isArray(current)) {
const keys = Reflect.ownKeys(current);
if (
keys.length !== current.length + 1 ||
keys.some(
(key) =>
key !== "length" &&
(typeof key !== "string" ||
!/^(0|[1-9]\d*)$/.test(key) ||
Number(key) >= current.length)
)
) {
throw strictJsonValidationError(
context,
"unsupported_object",
`${context.label} contains a non-JSON array property at ${path}`,
path
);
}
for (let index = 0; index < current.length; index++) {
const descriptor = Object.getOwnPropertyDescriptor(current, String(index));
if (
descriptor === undefined ||
!descriptor.enumerable ||
!("value" in descriptor)
) {
throw strictJsonValidationError(
context,
"unsupported_object",
`${context.label} contains a non-JSON array property at ${path}[${index}]`,
`${path}[${index}]`View on GitHub (pinned to cd8cf15dc3)