phalcon/cphalcon · error · Phalcon\Forms\Exceptions\JsonSchemaNotArray

JSON form schema must decode to an array

Error message

JSON form schema must decode to an array

What it means

After a successful JSON decode, JsonLoader requires the top-level document to be an array that is a list (sequential integer keys). A JSON object root decodes to an associative array and scalars/null decode to non-arrays — both throw JsonSchemaNotArray, because form definitions must be a numerically indexed list of entry arrays.

Source

Thrown at phalcon/Forms/Loader/JsonLoader.zep:65

     */
    public function load() -> array
    {
        var ex, definitions, json, loader;

        let json = this->source;

        if is_file(json) && is_readable(json) {
            let json = (string) this->phpFileGetContents(json);
        }

        try {
            let definitions = (new Decode())->__invoke(json, true, 512, JSON_THROW_ON_ERROR);
        } catch InvalidArgumentException, ex {
            throw new InvalidJsonSchema(ex->getMessage());
        }

        if typeof definitions !== "array" || !array_is_list(definitions) {
            throw new JsonSchemaNotArray();
        }

        let loader = new ArrayLoader(definitions);

        return loader->load();
    }
}

View on GitHub (pinned to b7419de9cd)

Solutions

  1. Make the top-level JSON document a list: [{...}, {...}]
  2. If a wrapper object is required, unwrap the inner list before passing it to JsonLoader
  3. Pre-check the shape: is_array($decoded) && array_is_list($decoded)

Example fix

// before — forms.json
{
  "version": 2,
  "forms": [
    { "type": "text", "name": "email" }
  ]
}

// after — forms.json
[
  { "type": "text", "name": "email" }
]
Defensive patterns

Strategy: validation

Validate before calling

$decoded = json_decode($json, true, 512, JSON_THROW_ON_ERROR);

if (!is_array($decoded) || !array_is_list($decoded)) {
    // unwrap known wrapper objects, or reject
    $decoded = $decoded['forms'] ?? null;
    if (!is_array($decoded) || !array_is_list($decoded)) {
        throw new \InvalidArgumentException('Form schema root must be a JSON list');
    }
}

Type guard

/** @param mixed $decoded */
function isDefinitionList($decoded): bool
{
    return is_array($decoded) && array_is_list($decoded);
}

Try / catch

try {
    $defs = (new \Phalcon\Forms\Loader\JsonLoader($source))->load();
} catch (\Phalcon\Forms\Exceptions\JsonSchemaNotArray $e) {
    // the root was an object or scalar; rewrite the file root as a list
    throw new \RuntimeException('Form schema root must be a JSON list of entries', 0, $e);
}

Prevention

When it happens

Trigger: A schema file whose root is a JSON object like {"forms": [...]} instead of [...]; a root-level string or number; a single entry written as an object rather than wrapped in a list.

Common situations: Wrapping the definition list in a top-level object to attach metadata (version, labels); exporting schemas from tools that default to emitting objects.

Related errors


AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21). Data as JSON: /api/errors/97a03dc31903667e. Report an issue: GitHub.