HelloZeroNet/ZeroNet · error · VerifyError

Includes not allowed

Error message

Includes not allowed

What it means

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.

Source

Thrown at src/Content/ContentManager.py:924

            if content_size_optional > rules["max_size_optional"]:
                raise VerifyError("Include optional files too large %sB > %sB" % (
                    content_size_optional, rules["max_size_optional"])
                )

        # Filename limit
        if rules.get("files_allowed"):
            for file_inner_path in list(content["files"].keys()):
                if not SafeRe.match(r"^%s$" % rules["files_allowed"], file_inner_path):
                    raise VerifyError("File not allowed: %s" % file_inner_path)

        if rules.get("files_allowed_optional"):
            for file_inner_path in list(content.get("files_optional", {}).keys()):
                if not SafeRe.match(r"^%s$" % rules["files_allowed_optional"], file_inner_path):
                    raise VerifyError("Optional file not allowed: %s" % file_inner_path)

        # Check if content includes allowed
        if rules.get("includes_allowed") is False and content.get("includes"):
            raise VerifyError("Includes not allowed")

        return True  # All good

    # Verify file validity
    # Return: None = Same as before, False = Invalid, True = Valid
    def verifyFile(self, inner_path, file, ignore_same=True):
        if inner_path.endswith("content.json"):  # content.json: Check using sign
            from Crypt import CryptBitcoin
            try:
                if type(file) is dict:
                    new_content = file
                else:
                    try:
                        if sys.version_info.major == 3 and sys.version_info.minor < 6:
                            new_content = json.loads(file.read().decode("utf8"))
                        else:
                            new_content = json.load(file)
                    except Exception as err:

View on GitHub (pinned to 454c0b2e7e)

Solutions

  1. Remove the 'includes' key from the content.json you are publishing, since the site rules disallow includes
  2. If includes are legitimately needed, change the site's content.json rules to "includes_allowed": true, re-sign, and publish
  3. 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

Example fix

// before (content.json)
{"rules": {"includes_allowed": false}, "includes": {"users/content.json": {"signers": [], "files_allowed": "data.json"}}, ...}
// after
{"rules": {"includes_allowed": false}, "files": {...}}  // includes removed, or set includes_allowed: true and re-sign
Defensive patterns

Strategy: validation

Validate before calling

import json
content = json.load(open('content.json'))
rules = json.load(open('data/<site>/content.json')).get('rules', {})
if rules.get('includes_allowed') is False and content.get('includes'):
    raise ValueError('content.json contains includes but site forbids them')

Type guard

def includes_allowed(content, rules):
    return not (rules.get('includes_allowed') is False and content.get('includes'))

Try / catch

from Content.ContentManager import VerifyError
try:
    site.content_manager.verifyContent(inner_path, content)
except VerifyError as e:
    if 'Includes not allowed' in str(e):
        content.pop('includes', None); content = resign(content)
    else:
        raise

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of HelloZeroNet/ZeroNet@454c0b2e7e (2026-09-02). Data as JSON: /api/errors/26669565c410079e. Report an issue: GitHub.