{"record":{"id":"57bc3eefb7056471","repo":"OpenHands/OpenHands","slug":"field-label-must-be-a-json-object","errorCode":null,"errorMessage":"${field.label} must be a JSON object","messagePattern":"(.+?) must be a JSON object","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/utils/sdk-settings-schema.ts","lineNumber":397,"sourceCode":"    try {\n      parsedValue = JSON.parse(stringValue);\n    } catch {\n      throw new Error(`Invalid JSON for ${field.label}`);\n    }\n\n    if (field.value_type === \"array\") {\n      if (!Array.isArray(parsedValue)) {\n        throw new Error(`${field.label} must be a JSON array`);\n      }\n      return parsedValue as SettingsValue[];\n    }\n\n    if (\n      parsedValue === null ||\n      Array.isArray(parsedValue) ||\n      typeof parsedValue !== \"object\"\n    ) {\n      throw new Error(`${field.label} must be a JSON object`);\n    }\n\n    return parsedValue as { [key: string]: SettingsValue };\n  }\n\n  const stringValue = String(rawValue);\n  if (stringValue === \"\" && !field.secret) {\n    return null;\n  }\n\n  return stringValue;\n}\n\nexport function buildSdkSettingsPayload(\n  schema: SettingsSchema,\n  values: SettingsFormValues,\n  dirty: SettingsDirtyState,\n): SdkSettingsPayload {","sourceCodeStart":379,"sourceCodeEnd":415,"githubUrl":"https://github.com/OpenHands/OpenHands/blob/500b4c533e9393e44cb92894bcbb18438ef473b6/src/utils/sdk-settings-schema.ts#L379-L415","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Enter a plain JSON object: '{ \"key\": value }'.","To clear an object field, leave the input empty (the empty-string check returns null before JSON.parse).","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."],"exampleFix":"// before\ncoerceFieldValue(objectField, '[1, 2, 3]');  // throws\n// after\ncoerceFieldValue(objectField, '{ \"a\": 1 }');  // returns { a: 1 }","handlingStrategy":"validation","validationCode":"function isJsonObjectString(value: string): boolean {\n  try {\n    const parsed = JSON.parse(value);\n    return typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed);\n  } catch { return false; }\n}\n// if (raw.trim() !== '' && !isJsonObjectString(raw)) showFieldError(field, 'Enter a JSON object');","typeGuard":null,"tryCatchPattern":"try {\n  const coerced = coerceFieldValue(objectField, rawValue);\n} catch (error) {\n  if (error instanceof Error && error.message.endsWith('must be a JSON object')) {\n    setFieldError(objectField.key, 'Top-level value must be a JSON object ({...})');\n  } else throw error;\n}","preventionTips":["Confirm the field's value_type is 'object' before assuming array input is acceptable.","Show a placeholder like '{ \"key\": value }' in object field inputs.","To clear an object field, leave the input empty (empty string returns null) rather than entering 'null'."],"tags":["settings","schema","validation","json","object"],"backgroundTag":null,"analyzedSha":"500b4c533e9393e44cb92894bcbb18438ef473b6","analyzedAt":"2026-08-12T10:07:46.034Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}