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
- Make the top-level JSON document a list: [{...}, {...}]
- If a wrapper object is required, unwrap the inner list before passing it to JsonLoader
- 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
- Standardize schema files to start with '[' — never a wrapper object
- Keep metadata (version, labels) in a sibling file or non-schema config key
- Add a CI schema check asserting array_is_list(json_decode(file, true))
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
- JSON form schema is invalid: {detail}
- YAML form schema must parse to an array
- Unknown form element type "{type}"
- Form schema definition at index {index} must be an array
- Form schema definition at index {index} is missing required
AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21).
Data as JSON: /api/errors/97a03dc31903667e.
Report an issue: GitHub.