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
- Delete the local file (data/<site>/<inner_path>) and re-download it from other peers
- If you modified the file locally, re-publish the site so content.json is regenerated with new sha512 hashes
- Verify manually: python -c "import hashlib;print(hashlib.sha512(open('file','rb').read()).hexdigest())" and compare to content.json
- 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
- Re-sign content.json after every file edit (hashes must match)
- Re-download any file failing verification before retrying
- Investigate disk/network health if corruption repeats
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
- Invalid hash
- Includes not allowed
- Invalid json file: %s
- We have newer (Our: %s, Sent: %s)
- Modify timestamp is in the far future!
AI-assisted analysis of HelloZeroNet/ZeroNet@454c0b2e7e (2026-09-02).
Data as JSON: /api/errors/623e63af6cbc6348.
Report an issue: GitHub.