OpenHands/OpenHands · warning

${field.label} must be a JSON object

Error message

${field.label} must be a JSON object

What it means

Thrown by coerceFieldValue for an object settings field when JSON.parse succeeds but the parsed value is null, an array, or a non-object primitive. The field's value_type is 'object', so the top-level JSON must be a plain object (typeof === 'object', not null, not Array). Symmetric to error 56 for the object case.

Source

Thrown at src/utils/sdk-settings-schema.ts:397

    try {
      parsedValue = JSON.parse(stringValue);
    } catch {
      throw new Error(`Invalid JSON for ${field.label}`);
    }

    if (field.value_type === "array") {
      if (!Array.isArray(parsedValue)) {
        throw new Error(`${field.label} must be a JSON array`);
      }
      return parsedValue as SettingsValue[];
    }

    if (
      parsedValue === null ||
      Array.isArray(parsedValue) ||
      typeof parsedValue !== "object"
    ) {
      throw new Error(`${field.label} must be a JSON object`);
    }

    return parsedValue as { [key: string]: SettingsValue };
  }

  const stringValue = String(rawValue);
  if (stringValue === "" && !field.secret) {
    return null;
  }

  return stringValue;
}

export function buildSdkSettingsPayload(
  schema: SettingsSchema,
  values: SettingsFormValues,
  dirty: SettingsDirtyState,
): SdkSettingsPayload {

View on GitHub (pinned to 500b4c533e)

Solutions

  1. Enter a plain JSON object: '{ "key": value }'.
  2. To clear an object field, leave the input empty (the empty-string check returns null before JSON.parse).
  3. Confirm the field's value_type in /api/settings/agent-schema — if it is 'object', the top-level JSON must be a curly-braced object.

Example fix

// before
coerceFieldValue(objectField, '[1, 2, 3]');  // throws
// after
coerceFieldValue(objectField, '{ "a": 1 }');  // returns { a: 1 }
Defensive patterns

Strategy: validation

Validate before calling

function isJsonObjectString(value: string): boolean {
  try {
    const parsed = JSON.parse(value);
    return typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed);
  } catch { return false; }
}
// if (raw.trim() !== '' && !isJsonObjectString(raw)) showFieldError(field, 'Enter a JSON object');

Try / catch

try {
  const coerced = coerceFieldValue(objectField, rawValue);
} catch (error) {
  if (error instanceof Error && error.message.endsWith('must be a JSON object')) {
    setFieldError(objectField.key, 'Top-level value must be a JSON object ({...})');
  } else throw error;
}

Prevention

When it happens

Trigger: User enters valid JSON that is not an object into an object-typed field — e.g. '[1,2,3]' (array), 'null', '"string"', or '42'. JSON.parse succeeds, the null/array/primitive check fails, guard throws.

Common situations: User enters an array where an object is expected; user enters 'null' expecting it to clear the field (empty string clears, not null); type confusion between object and array fields; user wraps the object in an array.

Related errors


AI-assisted analysis of OpenHands/OpenHands@500b4c533e (2026-08-12). Data as JSON: /api/errors/57bc3eefb7056471. Report an issue: GitHub.