stamparm/maltrail · error · SystemExit

[!] no VERSION assignment in core/settings.py

Error message

[!] no VERSION assignment in core/settings.py

What it means

bump_version.py reads the current version by regex-matching a top-level `VERSION = "x.y"` assignment in core/settings.py. If the regex finds no match, it aborts with this SystemExit. It throws because the tool cannot safely compute the next version without a canonical two-component VERSION assignment.

Solutions

  1. Open core/settings.py and restore a top-level two-component assignment like VERSION = "0.5".
  2. Check the file path: the script resolves core/settings.py relative to its ROOT, so run it from a checkout that actually contains core/settings.py.
  3. If the variable was renamed or quoted differently, either rename it back or update the regex in current() to match the new format.

Example fix

// before (core/settings.py)
MALTRAIL_VERSION = '0.5'
// after
VERSION = "0.5"
Defensive patterns

Strategy: validation

Validate before calling

import re
text = open('core/settings.py').read()
if not re.search(r'^VERSION\s*=\s*"([^"]+)"', text, re.M):
    raise RuntimeError('core/settings.py lacks a VERSION = "x.y" assignment')

Type guard

def has_version_assignment(text: str) -> bool:
    return re.search(r'^VERSION\s*=\s*"([^"]+)"', text, re.M) is not None

Try / catch

try:
    bump_version.main(['--next'])
except SystemExit as e:
    if 'no VERSION assignment' in str(e):
        fix_settings_version_file()

Prevention

When it happens

Trigger: Running `python sensor/tools/bump_version.py --next` (or --version) when core/settings.py has no line starting with `VERSION = "..."` (exact spacing/name per regex `^VERSION\s*=\s*"([^"]+)"` in multiline mode).

Common situations: A refactor renamed the variable (e.g. CURRENT_VERSION), switched to single quotes, moved the version into a config file/pyproject.toml, added a comment prefix before VERSION, or core/settings.py is missing/stale in a build checkout.

Understand the failure class

Background: "missing required config value" errors: why libraries refuse to start when a configuration key is empty, unset, or blank — this error's family across 48 libraries.

Related errors


AI-assisted analysis of stamparm/maltrail@77cfb06d76 (2026-09-13). Data as JSON: /api/errors/f223cd5c54778cc3. Report an issue: GitHub.

Appendix: source

Thrown at sensor/tools/bump_version.py:72

         r'^(VERSION\s*=\s*")[^"]*(")', r'\g<1>%s\g<2>' % version),
        (os.path.join(ROOT, "sensor", "Cargo.toml"),
         r'^(version\s*=\s*")[^"]*(")', r'\g<1>%s\g<2>' % cargo),
        # anchored to the package entry: a bare ^version in a lock file would match every
        # dependency in it
        (os.path.join(ROOT, "sensor", "Cargo.lock"),
         r'(name = "maltrail-sensor"\nversion = ")[^"]*(")', r'\g<1>%s\g<2>' % cargo),
        (os.path.join(ROOT, "CITATION.cff"),
         r'^(version\s*:\s*")[^"]*(")', r'\g<1>%s\g<2>' % version),
        (os.path.join(ROOT, "sensor", "src", "settings_gen.rs"),
         r'^(pub const VERSION: &str = ")[^"]*(";)', r'\g<1>%s\g<2>' % version),
    ]


def current():
    match = re.search(r'^VERSION\s*=\s*"([^"]+)"',
                      _read(os.path.join(ROOT, "core", "settings.py")), re.M)
    if not match:
        raise SystemExit("[!] no VERSION assignment in core/settings.py")
    return match.group(1)


def next_minor(version):
    parts = version.split(".")
    if len(parts) < 2 or not all(p.isdigit() for p in parts[:2]):
        raise SystemExit("[!] cannot bump %r - expected 'major.minor'" % version)
    return "%s.%d" % (parts[0], int(parts[1]) + 1)


def apply(version, date_released=None):
    """Rewrite every file, or none of them."""

    planned = []
    for path, pattern, repl in _edits(version):
        text = _read(path)
        new, n = re.subn(pattern, repl, text, flags=re.M)
        # Exactly once. Zero means the file moved on and this script is now lying about

View on GitHub (pinned to 77cfb06d76)