sveltejs/kit · error
Invalid array key ${keys[i + 1]}
Error message
Invalid array key ${keys[i + 1]} What it means
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'.
Source
Thrown at packages/kit/src/runtime/form-utils.js:521
* Sets a value in a nested object using an array of keys, mutating the original object.
* @param {Record<string, any>} object
* @param {string[]} keys
* @param {any} value
*/
export function deep_set(object, keys, value) {
let current = object;
for (let i = 0; i < keys.length - 1; i += 1) {
const key = keys[i];
check_prototype_pollution(key);
const is_array = /^\d+$/.test(keys[i + 1]);
const inner = Object.hasOwn(current, key) ? current[key] : undefined;
const exists = inner != null;
if (exists && is_array !== Array.isArray(inner)) {
throw new Error(`Invalid array key ${keys[i + 1]}`);
}
if (!exists) {
if (value === DELETE_KEY) {
// don't create the nested structure if we want to delete the key anyway
return;
}
current[key] = is_array ? [] : {};
}
current = current[key];
}
const final_key = keys[keys.length - 1];
check_prototype_pollution(final_key);
if (value === DELETE_KEY) {
delete current[final_key];View on GitHub (pinned to 03f1687fe6)
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.
Example fix
// before
fields.as('items');
fields.as('items[0]'); // conflicts: 'items' as scalar and array
// after
fields.as('items', { array: true });
fields.as('items[0]'); Defensive patterns
Strategy: validation
Validate before calling
const containers = {};
for (const name of fieldNames) {
const m = name.match(/^([^.\[]+)/);
if (m) containers[m[1]] = (containers[m[1]] ?? 0) | (/^\w+\[\d+\]/.test(name) ? 1 : 2);
if (containers[m[1]] === 3) throw new Error(`key '${m[1]}' used as both array and object`);
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Form cannot contain duplicated keys — "${field.name}" has ${
- Invalid field name ${path}: field names are written in JS ob
- Invalid environment variable name ${JSON.stringify(name)}
- Character escape sequence in ${id} must be lowercase
- use:enhance can only be used on <form> fields with method="P
AI-assisted analysis of sveltejs/kit@03f1687fe6 (2026-09-02).
Data as JSON: /api/errors/b408529036e7d384.
Report an issue: GitHub.