HelloZeroNet/ZeroNet · error · VerifyError

Invalid hash

Error message

Invalid hash

What it means

verifyFile raises VerifyError('Invalid hash') when verifying a regular (non-content.json) file: the file's sha512 (CryptHash.sha512sum) does not match the 'sha512' recorded for it in its parent content.json (via getFileInfo). This guarantees file integrity — the downloaded file differs from what the signed content.json declares.

Source

Thrown at src/Content/ContentManager.py:1012

                            valid_signs += CryptBitcoin.verify(sign_content, address, signs[address])
                        if valid_signs >= signs_required:
                            break  # Break if we has enough signs
                    if valid_signs < signs_required:
                        raise VerifyError("Valid signs: %s/%s" % (valid_signs, signs_required))
                    else:
                        return self.verifyContent(inner_path, new_content)
                else:  # Old style signing
                    raise VerifyError("Invalid old-style sign")

            except Exception as err:
                self.log.warning("%s: verify sign error: %s" % (inner_path, Debug.formatException(err)))
                raise err

        else:  # Check using sha512 hash
            file_info = self.getFileInfo(inner_path)
            if file_info:
                if CryptHash.sha512sum(file) != file_info.get("sha512", ""):
                    raise VerifyError("Invalid hash")

                if file_info.get("size", 0) != file.tell():
                    raise VerifyError(
                        "File size does not match %s <> %s" %
                        (inner_path, file.tell(), file_info.get("size", 0))
                    )

                return True

            else:  # File not in content.json
                raise VerifyError("File not in content.json")

    def optionalDelete(self, inner_path):
        self.site.storage.delete(inner_path)

    def optionalDownloaded(self, inner_path, hash_id, size=None, own=False):
        if size is None:
            size = self.site.storage.getSize(inner_path)

View on GitHub (pinned to 454c0b2e7e)

Solutions

  1. Delete the local file (data/<site>/<inner_path>) and re-download it from other peers
  2. If you modified the file locally, re-publish the site so content.json is regenerated with new sha512 hashes
  3. Verify manually: python -c "import hashlib;print(hashlib.sha512(open('file','rb').read()).hexdigest())" and compare to content.json
  4. Check disk health if corruption recurs repeatedly

Example fix

// before: changed index.html without re-signing content.json
{"files": {"index.html": {"sha512": "OLDHASH"}}}
// after: re-sign so hashes update
site_manager.getSite(address).signContent(privatekey)  // then publish
Defensive patterns

Strategy: validation

Validate before calling

import hashlib, json
content = json.load(open('data/<site>/content.json'))
path = 'index.html'
expected = content['files'][path]['sha512']
actual = hashlib.sha512(open('data/<site>/' + path, 'rb').read()).hexdigest()
assert actual == expected, 'file hash mismatch — re-download or re-publish'

Try / catch

from Content.ContentManager import VerifyError
try:
    site.content_manager.isModified(inner_path, file)
except VerifyError as e:
    if str(e) == 'Invalid hash':
        os.remove('data/<site>/' + inner_path); site.needFile(inner_path)  # re-fetch
    else:
        raise

Prevention

When it happens

Trigger: isModified -> verifyFile for a normal file: getFileInfo finds file_info from the site's content.json, and CryptHash.sha512sum(file) != file_info['sha512'] — the downloaded bytes are corrupt, modified, or the content.json hash entry doesn't match the local file.

Common situations: Bit-flip corruption during transfer, a peer serving tampered files, a locally modified file without re-publishing (hash in content.json now stale), or publishing files after signing content.json so hashes don't match.

Related errors


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