HelloZeroNet/ZeroNet · error · VerifyError

Invalid json file: %s

Error message

Invalid json file: %s

What it means

verifyFile raises VerifyError('Invalid json file: %s') when a downloaded content.json cannot be parsed as UTF-8 JSON. The exception message embeds the underlying json.loads/json.load error. It means the file received from the peer is corrupt, truncated, or not JSON at all, so no further verification can proceed.

Source

Thrown at src/Content/ContentManager.py:943

        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:
                        raise VerifyError("Invalid json file: %s" % err)
                if inner_path in self.contents:
                    old_content = self.contents.get(inner_path, {"modified": 0})
                    # Checks if its newer the ours
                    if old_content["modified"] == new_content["modified"] and ignore_same:  # Ignore, have the same content.json
                        return None
                    elif old_content["modified"] > new_content["modified"]:  # We have newer
                        raise VerifyError(
                            "We have newer (Our: %s, Sent: %s)" %
                            (old_content["modified"], new_content["modified"])
                        )
                if new_content["modified"] > time.time() + 60 * 60 * 24:  # Content modified in the far future (allow 1 day+)
                    raise VerifyError("Modify timestamp is in the far future!")
                if self.isArchived(inner_path, new_content["modified"]):
                    if inner_path in self.site.bad_files:
                        del self.site.bad_files[inner_path]
                    raise VerifyError("This file is archived!")
                # Check sign
                sign = new_content.get("sign")

View on GitHub (pinned to 454c0b2e7e)

Solutions

  1. Re-download the content.json: delete the file locally (site data dir) so it is fetched again from a healthy peer
  2. Check the file on disk (data/<site>/content.json) — if truncated or HTML, the peer/transport is bad; try other peers
  3. Validate it manually with python -m json.tool data/<site>/content.json to see the exact JSON error
  4. Ensure the file is UTF-8 encoded; convert or re-save it if a tool wrote another encoding

Example fix

// before: serving a content.json edited by a tool that emitted invalid JSON
{"modified": 1500000000, "files": {"index.html": {"sha512": "abc"},,} }
// after: valid JSON
{"modified": 1500000000, "files": {"index.html": {"sha512": "abc"}}}
Defensive patterns

Strategy: validation

Validate before calling

import json
def valid_json_file(path):
    try:
        with open(path, 'rb') as f:
            json.loads(f.read().decode('utf8'))
        return True
    except (UnicodeDecodeError, ValueError):
        return False

Try / catch

from Content.ContentManager import VerifyError
try:
    site.content_manager.isModified(inner_path, file)
except VerifyError as e:
    if str(e).startswith('Invalid json file'):
        redownload(inner_path)  # delete file and fetch from other peers
    else:
        raise

Prevention

When it happens

Trigger: verifyFile is called by isModified while verifying an incoming content.json; the file body fails json.loads (Python <3.6 path decodes utf8 first, otherwise json.load reads the file object) and raises, which is re-raised as VerifyError.

Common situations: Truncated downloads from peers, a peer serving an HTML error page instead of content.json, wrong encoding (e.g. UTF-16 or BOM issues on old Python), or a locally corrupted data directory after an interrupted write.

Understand the failure class

Related errors


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