{"record":{"id":"4256630e28d4a4cc","repo":"getgrav/grav","slug":"500","errorCode":"500","errorMessage":"Iterable should return username (string).","messagePattern":"Iterable should return username \\(string\\)\\.","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":500,"severity":"error","filePath":"system/src/Grav/Framework/Flex/Pages/Traits/PageAuthorsTrait.php","lineNumber":104,"sourceCode":"\n        return $this->_permissionsCache;\n    }\n\n    /**\n     * @param iterable $authors\n     * @return array<int,UserInterface>\n     */\n    protected function loadAuthors(iterable $authors): array\n    {\n        $accounts = $this->loadAccounts();\n        if (null === $accounts || empty($authors)) {\n            return [];\n        }\n\n        $list = [];\n        foreach ($authors as $username) {\n            if (!is_string($username)) {\n                throw new InvalidArgumentException('Iterable should return username (string).', 500);\n            }\n            $list[] = $accounts->load($username);\n        }\n\n        return $list;\n    }\n\n    /**\n     * @param string $action\n     * @param string|null $scope\n     * @param UserInterface|null $user\n     * @param bool $isAuthor\n     * @return bool|null\n     */\n    public function isParentAuthorized(string $action, ?string $scope = null, ?UserInterface $user = null, bool $isAuthor = false): ?bool\n    {\n        $scope ??= $this->getAuthorizeScope();\n","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/getgrav/grav/blob/6040efed04efa69b8209448ed81308e7c24147c2/system/src/Grav/Framework/Flex/Pages/Traits/PageAuthorsTrait.php#L86-L122","documentation":"PageAuthorsTrait::loadAuthors() iterates the 'header.permissions.authors' frontmatter value and requires every yielded element to be a username string; any non-string (nested array, map, number) throws InvalidArgumentException with code 500. The authors list must be a flat list of username strings; anything else is considered malformed page metadata.","triggerScenarios":"Frontmatter like permissions: {authors: [{name: jane}]} (list of maps) or authors: {jane: owner} where a value is an array; numeric usernames stored as YAML integers (authors: [123]); JSON-style nested objects under header.permissions.authors.","commonSituations":"Content authors writing structured author metadata instead of plain usernames; migrating legacy page metadata into permissions.authors without normalizing; plugins writing nested author objects into page headers.","solutions":["Fix the page frontmatter so authors is a flat list of quoted username strings: permissions: { authors: [jane, john] }.","Quote numeric-looking usernames so YAML keeps them strings: authors: ['12345'].","Normalize data before it reaches the page: in onAdminSave, map author entries to strings (e.g. $author['name'] ?? null).","Catch InvalidArgumentException when rendering author-dependent fields to show a clearer admin message naming the page."],"exampleFix":"# before (page frontmatter)\npermissions:\n  authors:\n    - { name: jane, role: owner }\n\n# after\npermissions:\n  authors: [jane]","handlingStrategy":"validation","validationCode":"// Normalize authors to a flat list of username strings before use/save\n$authors = (array) $page->getNestedProperty('header.permissions.authors', []);\n$valid = array_filter($authors, 'is_string');\nif (count($valid) !== count($authors)) {\n    // reject or repair (e.g. extract 'name' keys) before the page is used\n    $authors = array_map(\n        fn($a) => is_string($a) ? $a : ($a['name'] ?? null),\n        $authors\n    );\n    $page->setNestedProperty('header.permissions.authors', array_filter($authors));\n}","typeGuard":"function isUsernameList(mixed $authors): bool\n{\n    if (!is_iterable($authors)) { return false; }\n    foreach ($authors as $username) {\n        if (!is_string($username)) { return false; }\n    }\n    return true;\n}","tryCatchPattern":null,"preventionTips":["Author frontmatter must be a flat list of quoted usernames (authors: [jane, john]).","Quote numeric usernames so YAML keeps them strings.","Normalize on save via onAdminSave hooks in plugins that write author metadata."],"tags":["grav","flex","frontmatter","authors","validation"],"backgroundTag":"invalid-argument-type","analyzedSha":"6040efed04efa69b8209448ed81308e7c24147c2","analyzedAt":"2026-08-17T05:07:31.593Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}