HelloZeroNet/ZeroNet · error · VerifyError

Invalid old-style sign

Error message

Invalid old-style sign

What it means

verifyFile raises VerifyError('Invalid old-style sign') when the content.json does not use the modern multi-signature layout (no valid signers/signs structure could be processed) and falls into the legacy 'old style signing' branch, which ZeroNet no longer accepts here. Old-style content.json had a single 'sign' made over a differently-serialized body; such files must be re-signed with the current scheme.

Source

Thrown at src/Content/ContentManager.py:1002

                        signers_data = "%s:%s" % (signs_required, ",".join(valid_signers))
                        if not CryptBitcoin.verify(signers_data, self.site.address, new_content["signers_sign"]):
                            raise VerifyError("Invalid signers_sign!")

                    if inner_path != "content.json" and not self.verifyCert(inner_path, new_content):  # Check if cert valid
                        raise VerifyError("Invalid cert!")

                    valid_signs = 0
                    for address in valid_signers:
                        if address in signs:
                            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

View on GitHub (pinned to 454c0b2e7e)

Solutions

  1. Re-sign the content.json with the current signing scheme using CryptBitcoin.sign over the correct sign_content and place it in content['sign'][address] (single-signer modern format)
  2. Use the site owner's private key matching the site address
  3. Update your ZeroNet client and republish the site (Site:sign) so the content.json is regenerated in the accepted format

Example fix

// before: legacy layout
{"sign": "SINGLE_SIG_STRING", ...}
// after: modern layout
{"sign": {"<site_address>": "<sig>"}, ...}  // signed via CryptBitcoin.sign(sign_content, privatekey)
Defensive patterns

Strategy: validation

Validate before calling

import json
content = json.load(open('content.json'))
sign = content.get('sign')
if isinstance(sign, str):
    raise ValueError('legacy single-string sign detected; re-sign with modern format')
if not isinstance(sign, dict) and not content.get('signs'):
    raise ValueError('no valid signature structure found')

Type guard

def has_modern_sign(content):
    sign = content.get('sign')
    return isinstance(sign, dict) and len(sign) > 0

Try / catch

from Content.ContentManager import VerifyError
try:
    site.content_manager.isModified(inner_path, file)
except VerifyError as e:
    if str(e) == 'Invalid old-style sign':
        migrate_and_resign(site, privatekey)  # republish with modern signing
    else:
        raise

Prevention

When it happens

Trigger: isModified -> verifyFile: the new-style branch (signers/signs) is not taken — e.g. content lacks 'signs' or the sign-content reconstruction fails — and execution reaches the else branch labeled 'Old style signing', which unconditionally raises.

Common situations: Very old sites whose content.json was signed years ago with the legacy format and never re-signed; hand-crafted content.json missing the 'signs' dict; migration of a site from an old ZeroNet version without re-publishing.

Related errors


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