{"record":{"id":"b408529036e7d384","repo":"sveltejs/kit","slug":"invalid-array-key-keys-i-1","errorCode":null,"errorMessage":"Invalid array key ${keys[i + 1]}","messagePattern":"Invalid array key (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/kit/src/runtime/form-utils.js","lineNumber":521,"sourceCode":" * Sets a value in a nested object using an array of keys, mutating the original object.\n * @param {Record<string, any>} object\n * @param {string[]} keys\n * @param {any} value\n */\nexport function deep_set(object, keys, value) {\n\tlet current = object;\n\n\tfor (let i = 0; i < keys.length - 1; i += 1) {\n\t\tconst key = keys[i];\n\n\t\tcheck_prototype_pollution(key);\n\n\t\tconst is_array = /^\\d+$/.test(keys[i + 1]);\n\t\tconst inner = Object.hasOwn(current, key) ? current[key] : undefined;\n\t\tconst exists = inner != null;\n\n\t\tif (exists && is_array !== Array.isArray(inner)) {\n\t\t\tthrow new Error(`Invalid array key ${keys[i + 1]}`);\n\t\t}\n\n\t\tif (!exists) {\n\t\t\tif (value === DELETE_KEY) {\n\t\t\t\t// don't create the nested structure if we want to delete the key anyway\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcurrent[key] = is_array ? [] : {};\n\t\t}\n\n\t\tcurrent = current[key];\n\t}\n\n\tconst final_key = keys[keys.length - 1];\n\tcheck_prototype_pollution(final_key);\n\n\tif (value === DELETE_KEY) {\n\t\tdelete current[final_key];","sourceCodeStart":503,"sourceCodeEnd":539,"githubUrl":"https://github.com/sveltejs/kit/blob/03f1687fe612ce3d2d9131139b5b188d9cf90c64/packages/kit/src/runtime/form-utils.js#L503-L539","documentation":"deep_set walks a path like a[0].b to place a value; when it transitions into an array index it checks that the existing container is actually an array (and vice versa). If the path says the next segment is numeric but the current value is an object (or the reverse), the structure is inconsistent and it throws 'Invalid array key'.","triggerScenarios":"Mixing bracket-numeric and dot notation against the same base key, e.g. one submission posts items[0] and another posts items.0-shaped fields with different container types; two fields whose paths collide, one treating 'items' as an array and the other as an object.","commonSituations":"Dynamically generated field names where the same prefix is sometimes indexed and sometimes not; form schema changes between requests (array field converted to scalar) with stale client markup; hand-crafted posts mixing notations.","solutions":["Make the path consistent: use the same container type for a given key across all fields (always array indices or always object keys).","Declare the field as an array if multiple indexed values are submitted, so the container is created as an array.","Fix the specific conflicting segment reported (keys[i + 1]) — either rename the field or switch to a numeric index consistently."],"exampleFix":"// before\nfields.as('items');\nfields.as('items[0]'); // conflicts: 'items' as scalar and array\n// after\nfields.as('items', { array: true });\nfields.as('items[0]');","handlingStrategy":"validation","validationCode":"const containers = {};\nfor (const name of fieldNames) {\n  const m = name.match(/^([^.\\[]+)/);\n  if (m) containers[m[1]] = (containers[m[1]] ?? 0) | (/^\\w+\\[\\d+\\]/.test(name) ? 1 : 2);\n  if (containers[m[1]] === 3) throw new Error(`key '${m[1]}' used as both array and object`);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use one notation style per key: numeric indices only for arrays, named keys only for objects.","Declare array fields explicitly so the container is typed as an array.","Keep client field-generation and server schema in sync to avoid stale markup conflicts."],"tags":["forms","naming","data-conversion"],"backgroundTag":"inconsistent-array-path","analyzedSha":"03f1687fe612ce3d2d9131139b5b188d9cf90c64","analyzedAt":"2026-09-02T02:01:50.504Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}