{"record":{"id":"26669565c410079e","repo":"HelloZeroNet/ZeroNet","slug":"includes-not-allowed","errorCode":null,"errorMessage":"Includes not allowed","messagePattern":"Includes not allowed","errorType":"validation","errorClass":"VerifyError","httpStatus":null,"severity":"error","filePath":"src/Content/ContentManager.py","lineNumber":924,"sourceCode":"            if content_size_optional > rules[\"max_size_optional\"]:\n                raise VerifyError(\"Include optional files too large %sB > %sB\" % (\n                    content_size_optional, rules[\"max_size_optional\"])\n                )\n\n        # Filename limit\n        if rules.get(\"files_allowed\"):\n            for file_inner_path in list(content[\"files\"].keys()):\n                if not SafeRe.match(r\"^%s$\" % rules[\"files_allowed\"], file_inner_path):\n                    raise VerifyError(\"File not allowed: %s\" % file_inner_path)\n\n        if rules.get(\"files_allowed_optional\"):\n            for file_inner_path in list(content.get(\"files_optional\", {}).keys()):\n                if not SafeRe.match(r\"^%s$\" % rules[\"files_allowed_optional\"], file_inner_path):\n                    raise VerifyError(\"Optional file not allowed: %s\" % file_inner_path)\n\n        # Check if content includes allowed\n        if rules.get(\"includes_allowed\") is False and content.get(\"includes\"):\n            raise VerifyError(\"Includes not allowed\")\n\n        return True  # All good\n\n    # Verify file validity\n    # Return: None = Same as before, False = Invalid, True = Valid\n    def verifyFile(self, inner_path, file, ignore_same=True):\n        if inner_path.endswith(\"content.json\"):  # content.json: Check using sign\n            from Crypt import CryptBitcoin\n            try:\n                if type(file) is dict:\n                    new_content = file\n                else:\n                    try:\n                        if sys.version_info.major == 3 and sys.version_info.minor < 6:\n                            new_content = json.loads(file.read().decode(\"utf8\"))\n                        else:\n                            new_content = json.load(file)\n                    except Exception as err:","sourceCodeStart":906,"sourceCodeEnd":942,"githubUrl":"https://github.com/HelloZeroNet/ZeroNet/blob/454c0b2e7e000fda7000cba49027541fbf327b96/src/Content/ContentManager.py#L906-L942","documentation":"ContentManager.verifyContentInclude raises VerifyError('Includes not allowed') during content.json validation. ZeroNet sites declare rules in their content.json; if rules.includes_allowed is set to False, any incoming content.json that references nested content.json files via an 'includes' key is rejected. This protects merged/cloned sites from pulling in external sub-content the site owner explicitly disallowed.","triggerScenarios":"verifyContent is called (e.g. after downloading a peer's content.json via siteVerify/handshake or checkContents) and the incoming content.json contains a non-empty 'includes' object while the site's own rules have \"includes_allowed\": false.","commonSituations":"A site owner sets includes_allowed: false to lock down their site, then a user or peer tries to sync a modified content.json that adds includes (e.g. merging a cloned site or a user-content include); also happens when a plugin like ZeroMe references user-data includes on a site that forbids them.","solutions":["Remove the 'includes' key from the content.json you are publishing, since the site rules disallow includes","If includes are legitimately needed, change the site's content.json rules to \"includes_allowed\": true, re-sign, and publish","Verify you are syncing against the correct site — the rules come from the site's own content.json; a mixed/merged site may have stale rules"],"exampleFix":"// before (content.json)\n{\"rules\": {\"includes_allowed\": false}, \"includes\": {\"users/content.json\": {\"signers\": [], \"files_allowed\": \"data.json\"}}, ...}\n// after\n{\"rules\": {\"includes_allowed\": false}, \"files\": {...}}  // includes removed, or set includes_allowed: true and re-sign","handlingStrategy":"validation","validationCode":"import json\ncontent = json.load(open('content.json'))\nrules = json.load(open('data/<site>/content.json')).get('rules', {})\nif rules.get('includes_allowed') is False and content.get('includes'):\n    raise ValueError('content.json contains includes but site forbids them')","typeGuard":"def includes_allowed(content, rules):\n    return not (rules.get('includes_allowed') is False and content.get('includes'))","tryCatchPattern":"from Content.ContentManager import VerifyError\ntry:\n    site.content_manager.verifyContent(inner_path, content)\nexcept VerifyError as e:\n    if 'Includes not allowed' in str(e):\n        content.pop('includes', None); content = resign(content)\n    else:\n        raise","preventionTips":["Keep includes_allowed consistent with what you actually publish","Never merge foreign content.json edits into sites with includes_allowed: false","Re-sign and review rules after cloning a site"],"tags":["zeronet","content-verification","signing","includes"],"backgroundTag":"zeronet-verify-error","analyzedSha":"454c0b2e7e000fda7000cba49027541fbf327b96","analyzedAt":"2026-09-02T19:46:57.278Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}