QuantumNous/new-api · warning · Error
JSON must be an object
Error message
JSON must be an object
What it means
Thrown by normalizeJsonObject in the update-config dialog when parsing env_json or secret_env_json succeeds but the result is not a plain object (null, array, or primitive). It is a plain English literal (not i18n'd) raised during form submit/normalization before the config update is sent.
Source
Thrown at web/src/features/models/components/dialogs/update-config-dialog.tsx:69
traffic_port: z.coerce.number().int().min(1).max(65535).optional(),
entrypoint: z.string().optional(),
args: z.string().optional(),
command: z.string().optional(),
registry_username: z.string().optional(),
registry_secret: z.string().optional(),
env_json: z.string().optional(),
secret_env_json: z.string().optional(),
})
type Values = z.input<typeof schema>
const UPDATE_CONFIG_FORM_ID = 'update-config-form'
function normalizeJsonObject(input?: string) {
if (!input || !input.trim()) return undefined
const parsed = JSON.parse(input)
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
throw new Error('JSON must be an object')
}
return Object.fromEntries(
Object.entries(parsed as Record<string, unknown>).map(([k, v]) => [
k,
String(v),
])
) as Record<string, string>
}
export function UpdateConfigDialog({
open,
onOpenChange,
deploymentId,
}: {
open: boolean
onOpenChange: (open: boolean) => void
deploymentId: string | number | null
}) {View on GitHub (pinned to e2c7aa7b10)
Solutions
- Use a top-level object with string values: {"ENV_NAME": "value"}
- Wrap arrays as an object keyed by name instead of a list
- Leave the field blank/empty to omit it — blank returns undefined without parsing
- Ensure all values are strings (the normalizer String()s them, but start clean)
Example fix
// before
secret_env_json: '["API_KEY=xyz"]'
// after
secret_env_json: '{"API_KEY": "xyz"}' Defensive patterns
Strategy: validation
Validate before calling
const isJsonObjectString = (s?: string): boolean => {
if (!s?.trim()) return true
try {
const v: unknown = JSON.parse(s)
return !!v && typeof v === 'object' && !Array.isArray(v)
} catch { return false }
}
// disable submit unless isJsonObjectString(values.env_json) && isJsonObjectString(values.secret_env_json) Type guard
const isPlainObject = (v: unknown): v is Record<string, unknown> => typeof v === 'object' && v !== null && !Array.isArray(v)
Try / catch
try {
const env = normalizeJsonObject(values.env_json)
const secretEnv = normalizeJsonObject(values.secret_env_json)
// proceed with update
} catch (error) {
toast.error((error as Error).message) // 'JSON must be an object' or JSON.parse SyntaxError
} Prevention
- Validate env_json/secret_env_json shape on blur with a zod refinement, not only on submit
- Accept blank as 'omit' and document that null is not a valid value
- Wrap JSON.parse and rethrow a descriptive field-specific error
When it happens
Trigger: Entering env_json like ["A=1"] or "A=1" (bare string) or null in the update-config form; JSON.parse succeeds, the object check fails, submission aborts.
Common situations: Users paste a JSON array of env entries or a single-quoted string; copy env objects from docker-compose YAML converted incorrectly; assume null clears the field (empty string is the supported way).
Related errors
- Legacy format must be a JSON object
- Parameter override must be valid JSON format
- Channel is not selected
- Unexpected release payload
AI-assisted analysis of QuantumNous/new-api@e2c7aa7b10 (2026-08-15).
Data as JSON: /api/errors/3e456e1d355ecf02.
Report an issue: GitHub.