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
- Add the matching '<< if is_quadlet >>' (or '<< if not is_quadlet >>') line before the '<< else >>'
- Remove the stray '<< else >>' if the block is no longer conditional
- 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
- Keep every if/else/endif group inside a single options/*.md file — the stack is per render() call
- Add the lint above to the docs CI job so imbalance fails before the real run
- When deleting an '<< if >>' line, delete its else/endif in the same edit
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
- multiple `else` in the same `if`
- `end` without `if`
- unclosed `if` block(s)
- undefined variable: {name}
- Invalid inline if/else syntax: {inner}
AI-assisted analysis of podman-container-tools/podman@a2409076ef (2026-08-15).
Data as JSON: /api/errors/7e9dcd5e1ab09cc2.
Report an issue: GitHub.