GyulyVGC/sniffnet · error · SystemExit
Cannot parse debian/changelog
Error message
Cannot parse debian/changelog
What it means
prepare_staged() reads resources/packaging/linux/deb-source/debian/changelog and parses its first line with the regex ^sniffnet (<version>) <distribution>;. If the first line does not match this exact Debian changelog format, the version cannot be determined and the script aborts. The parser expects the standard Debian changelog header and does not tolerate deviating package names or missing fields.
Solutions
- Inspect the first line of resources/packaging/linux/deb-source/debian/changelog and fix it to match: sniffnet (<version>) <distro>; e.g. 'sniffnet (1.3.1-1) trixie;'
- Restore the changelog from git (git checkout -- resources/packaging/linux/deb-source/debian/changelog)
- If adding a new entry, use dch or copy an existing entry's header format exactly, keeping 'sniffnet', parentheses, and the trailing semicolon
Example fix
# before sniffnet 1.3.1 trixie; # after sniffnet (1.3.1) trixie;
Defensive patterns
Strategy: validation
Validate before calling
import re
first = open("resources/packaging/linux/deb-source/debian/changelog").readline()
if not re.match(r"sniffnet \(([^)]+)\) ([\w-]+);", first):
raise SystemExit("debian/changelog header is malformed") Type guard
def changelog_header_is_valid(text: str) -> bool:
return re.match(r"sniffnet \(([^)]+)\) ([\w-]+);", text) is not None Try / catch
try:
prepare(output)
except SystemExit as e:
if "Cannot parse debian/changelog" in str(e):
print("Fix debian/changelog first line to: sniffnet (<version>) <distro>;", file=sys.stderr)
raise Prevention
- Edit debian/changelog with dch instead of hand-editing the header
- Keep the exact header format: package name, parenthesized version, distribution, trailing semicolon
- Validate the changelog in CI before running the packager
- Restore the file from git if it was accidentally rewritten
When it happens
Trigger: Running prepare.py when the first line of debian/changelog is malformed: package name other than 'sniffnet' at line start, missing parenthesized version, missing distribution codename, missing trailing semicolon, or a changelog starting with blank lines or a comment.
Common situations: Hand-editing the changelog and breaking the header; renaming the package; an automated tool reformatting the changelog; a changelog file accidentally emptied or replaced with a template; missing closing semicolon after the distribution name.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
AI-assisted analysis of GyulyVGC/sniffnet@592a62a5ad (2026-09-18).
Data as JSON: /api/errors/c8b70c964e57403a.
Report an issue: GitHub.
Appendix: source
Thrown at resources/packaging/linux/deb-source/prepare.py:43
def prepare(output):
if output.exists() and any(output.iterdir()):
raise SystemExit(f"Refusing to overwrite an existing release in {output}; use --output with a fresh directory")
# Stage outside the checkout so Cargo cannot inherit a newer parent workspace.
with tempfile.TemporaryDirectory(prefix="sniffnet-debian-") as staging:
source = prepare_staged(Path(staging))
output.mkdir(parents=True, exist_ok=True)
for path in Path(staging).iterdir():
shutil.move(str(path), output / path.name)
print(f"Release files: {output}", flush=True)
return output / source.name
def prepare_staged(output):
changelog = (DEBIAN / "changelog").read_text()
match = re.match(r"sniffnet \(([^)]+)\) ([\w-]+);", changelog)
if not match:
raise SystemExit("Cannot parse debian/changelog")
version = match[1].rsplit("-", 1)[0]
tag = f"refs/tags/v{version}"
commit = run("git", "rev-parse", "--verify", f"{tag}^{{commit}}",
capture_output=True, text=True).stdout.strip()
manifest = tomllib.loads(run("git", "show", f"{commit}:Cargo.toml",
capture_output=True, text=True).stdout)
if manifest["package"]["version"] != version:
raise SystemExit("debian/changelog must match the tagged Cargo.toml version")
source = output / f"sniffnet-{version}"
archive = output / f"sniffnet_{version}.orig.tar.gz"
if source.exists() or archive.exists():
raise SystemExit(f"Refusing to overwrite an existing release in {output}; use --output with a fresh directory")
epoch = int(run("git", "show", "-s", "--format=%ct", commit,
capture_output=True, text=True).stdout)
output.mkdir(parents=True, exist_ok=True)
source.mkdir()
# Extract only release-tag inputs. A branch with the same name cannot winView on GitHub (pinned to 592a62a5ad)