podman-container-tools/podman · error · ValueError

`else` without `if`

Error message

`else` without `if`

What it means

Raised when render() encounters a '<< else >>' token while the control-block stack is empty. Each render() call processes exactly one file (an option file included via @@option), so an if/else/endif group must be fully balanced within a single file; an 'if' opened in another file does not count. The stack starts empty per file, hence any '<< else >>' seen before a '<< if ... >>' in the same file is fatal.

Source

Thrown at hack/markdown-preprocess:84

            return bool(get_variable(name))

        for m in TOK.finditer(text):
            # write literal up to token
            literal = text[pos:m.start()]
            if is_active():
                out.append(literal)
            pos = m.end()

            inner = m.group(1).strip()

            # control blocks
            if inner.startswith("if ") and len(inner[3:].strip().split(" ")) in [1, 2]:
                cond = inner[3:].strip()
                stack.append({"active": is_active() and truthy(cond), "seen_else": False})
                continue
            if inner == "else":
                if not stack:
                    raise ValueError("`else` without `if`")
                frame = stack[-1]
                if frame["seen_else"]:
                    raise ValueError("multiple `else` in the same `if`")
                frame["seen_else"] = True
                parent_active = all(f["active"] for f in stack[:-1])
                frame["active"] = parent_active and not frame["active"]
                continue
            if inner == "endif":
                if not stack:
                    raise ValueError("`end` without `if`")
                stack.pop()
                continue

            # inline "X if cond else Y" ---
            if " if " in inner and " else " in inner:
                try:
                    # split by " if " then " else "
                    then_part, rest = inner.split(" if ", 1)

View on GitHub (pinned to a2409076ef)

Solutions

  1. Add the matching '<< if is_quadlet >>' (or '<< if not is_quadlet >>') line before the '<< else >>'
  2. Remove the stray '<< else >>' if the block is no longer conditional
  3. If the if/endif pair lives in a different option file, move the whole if/else/endif group into one file

Example fix

# before (single options file)
<< else >>
Quadlet-specific text
<< endif >>

# after
<< if is_quadlet >>
Generic text
<< else >>
Quadlet-specific text
<< endif >>
Defensive patterns

Strategy: validation

Validate before calling

# Simulate the render() control stack before running the preprocessor
import re, pathlib
def lint(text, name):
    stack = 0
    for m in re.finditer(r'<<(.*?)>>', text, re.DOTALL):
        inner = m.group(1).strip()
        if inner.startswith('if ') and len(inner[3:].split()) in (1, 2):
            stack += 1
        elif inner == 'else':
            assert stack > 0, f'{name}: `else` without `if` near offset {m.start()}'
        elif inner == 'endif':
            assert stack > 0, f'{name}: `end` without `if` near offset {m.start()}'
            stack -= 1
    assert stack == 0, f'{name}: {stack} unclosed `if` block(s)'
for p in pathlib.Path('docs/source/markdown/options').glob('*.md'):
    lint(p.read_text(), str(p))

Prevention

When it happens

Trigger: An options/*.md file contains '<< else >>' with no preceding '<< if VAR >>' in that same file: the '<< if >>' line was deleted or commented out during editing, or the block was split across two option files, or an endif earlier in the file already popped the frame the else belonged to.

Common situations: Editing shared option files that are included by many man pages; merging branch text and accidentally removing the if-line; trying to use else in the top-level .md.in file (where render() is never called, tokens pass through and hit replace_type instead).

Related errors


AI-assisted analysis of podman-container-tools/podman@a2409076ef (2026-08-15). Data as JSON: /api/errors/7e9dcd5e1ab09cc2. Report an issue: GitHub.