{"record":{"id":"97a03dc31903667e","repo":"phalcon/cphalcon","slug":"json-form-schema-must-decode-to-an-array","errorCode":null,"errorMessage":"JSON form schema must decode to an array","messagePattern":"JSON form schema must decode to an array","errorType":"exception","errorClass":"Phalcon\\Forms\\Exceptions\\JsonSchemaNotArray","httpStatus":null,"severity":"error","filePath":"phalcon/Forms/Loader/JsonLoader.zep","lineNumber":65,"sourceCode":"     */\n    public function load() -> array\n    {\n        var ex, definitions, json, loader;\n\n        let json = this->source;\n\n        if is_file(json) && is_readable(json) {\n            let json = (string) this->phpFileGetContents(json);\n        }\n\n        try {\n            let definitions = (new Decode())->__invoke(json, true, 512, JSON_THROW_ON_ERROR);\n        } catch InvalidArgumentException, ex {\n            throw new InvalidJsonSchema(ex->getMessage());\n        }\n\n        if typeof definitions !== \"array\" || !array_is_list(definitions) {\n            throw new JsonSchemaNotArray();\n        }\n\n        let loader = new ArrayLoader(definitions);\n\n        return loader->load();\n    }\n}\n","sourceCodeStart":47,"sourceCodeEnd":73,"githubUrl":"https://github.com/phalcon/cphalcon/blob/b7419de9cd0a8a3f48441ead84c9f8415d463e25/phalcon/Forms/Loader/JsonLoader.zep#L47-L73","documentation":"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.","triggerScenarios":"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.","commonSituations":"Wrapping the definition list in a top-level object to attach metadata (version, labels); exporting schemas from tools that default to emitting objects.","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)"],"exampleFix":"// before — forms.json\n{\n  \"version\": 2,\n  \"forms\": [\n    { \"type\": \"text\", \"name\": \"email\" }\n  ]\n}\n\n// after — forms.json\n[\n  { \"type\": \"text\", \"name\": \"email\" }\n]","handlingStrategy":"validation","validationCode":"$decoded = json_decode($json, true, 512, JSON_THROW_ON_ERROR);\n\nif (!is_array($decoded) || !array_is_list($decoded)) {\n    // unwrap known wrapper objects, or reject\n    $decoded = $decoded['forms'] ?? null;\n    if (!is_array($decoded) || !array_is_list($decoded)) {\n        throw new \\InvalidArgumentException('Form schema root must be a JSON list');\n    }\n}","typeGuard":"/** @param mixed $decoded */\nfunction isDefinitionList($decoded): bool\n{\n    return is_array($decoded) && array_is_list($decoded);\n}","tryCatchPattern":"try {\n    $defs = (new \\Phalcon\\Forms\\Loader\\JsonLoader($source))->load();\n} catch (\\Phalcon\\Forms\\Exceptions\\JsonSchemaNotArray $e) {\n    // the root was an object or scalar; rewrite the file root as a list\n    throw new \\RuntimeException('Form schema root must be a JSON list of entries', 0, $e);\n}","preventionTips":["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))"],"tags":["phalcon","forms","json","schema","structure"],"backgroundTag":"invalid-json-structure","analyzedSha":"b7419de9cd0a8a3f48441ead84c9f8415d463e25","analyzedAt":"2026-08-21T06:21:18.811Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}