QuantumNous/new-api · warning · Error

Legacy format must be a JSON object

Error message

Legacy format must be a JSON object

What it means

Thrown by buildVisualJson when the legacy text is syntactically valid JSON but JSON.parse yields null, a primitive (string/number/boolean), or an Array. The override format requires a top-level JSON object, so anything else is rejected before re-serialization.

Source

Thrown at web/src/features/channels/components/dialogs/param-override-editor-dialog.tsx:1486

      }
      resetDragState()
    },
    [draggedOperationId, dragOverOperationId, dragOverPosition, resetDragState]
  )

  // ---------------------------------------------------------------------------
  // Mode switching & templates
  // ---------------------------------------------------------------------------

  const buildVisualJson = useCallback((): string => {
    if (visualMode === 'legacy') {
      const trimmed = legacyValue.trim()
      if (!trimmed) return ''
      if (!verifyJSON(trimmed))
        throw new Error(t('Parameter override must be valid JSON format'))
      const parsed = JSON.parse(trimmed) as unknown
      if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
        throw new Error(t('Legacy format must be a JSON object'))
      return JSON.stringify(parsed, null, 2)
    }
    return buildOperationsJson(operations, { validate: true }, t)
  }, [legacyValue, operations, t, visualMode])

  const switchToJsonMode = useCallback(() => {
    if (editMode === 'json') return
    try {
      setJsonText(buildVisualJson())
      setJsonError('')
    } catch (error) {
      toast.error((error as Error).message)
      if (visualMode === 'legacy') {
        setJsonText(legacyValue)
      } else {
        setJsonText(buildOperationsJson(operations, { validate: false }, t))
      }
      setJsonError(

View on GitHub (pinned to e2c7aa7b10)

Solutions

  1. Wrap the content in a top-level object: change ["k":"v"] to {"k":"v"}
  2. If the value is a bare primitive, give it a key, e.g. "gpt-4o" → {"model": "gpt-4o"}
  3. Check for null literal — an empty field is fine (returns early) but the text null is not
  4. Validate shape in a console: JSON.parse(text) must give typeof 'object' and not Array.isArray

Example fix

// before
[
  { "upstream": "openai" }
]
// after
{
  "upstream": "openai"
}
Defensive patterns

Strategy: type-guard

Validate before calling

const parsed = JSON.parse(trimmed) as unknown
const isJsonObject = !!parsed && typeof parsed === 'object' && !Array.isArray(parsed)
if (!isJsonObject) { /* show inline shape error */ }

Type guard

const isPlainObject = (v: unknown): v is Record<string, unknown> =>
  typeof v === 'object' && v !== null && !Array.isArray(v)

Try / catch

try {
  const parsed: unknown = JSON.parse(trimmed)
  if (!isPlainObject(parsed)) throw new Error(t('Legacy format must be a JSON object'))
} catch (error) {
  toast.error((error as Error).message)
}

Prevention

When it happens

Trigger: Legacy field contains e.g. ["gpt-4o"] (array), "gpt-4o" (bare string), 42, or the literal null — parse succeeds, the object check fails, and this error is toasted during the mode switch.

Common situations: User wrapped the override in brackets thinking it is a list of overrides; pasted a single string value; copied a JSON fragment from a config that stores overrides as an array.

Related errors


AI-assisted analysis of QuantumNous/new-api@e2c7aa7b10 (2026-08-15). Data as JSON: /api/errors/47b9dc1d6033e062. Report an issue: GitHub.