podman-container-tools/podman · error · ValueError
unclosed `if` block(s)
Error message
unclosed `if` block(s)
What it means
Raised at the end of render() when the control-block stack is still non-empty: at least one '<< if ... >>' was never closed with '<< endif >>'. Unclosed blocks also silently swallow the file's trailing literal (it is only appended when is_active()). A typo'd closer such as '<< end >>' or '<< ENDIF >>' is not recognized (it is preserved verbatim as an unrecognized token) and leaves the frame open, producing this error at EOF.
Source
Thrown at hack/markdown-preprocess:122
cond = cond.strip()
chosen = then_part if truthy(cond) else else_part
if is_active():
out.append(chosen.strip().strip("'\""))
except Exception as e:
raise ValueError(f"Invalid inline if/else syntax: {inner}") from e
continue
# Unrecognized token (e.g. `<<a|b>>` for replace_type, or `<<subcommand>>`):
# preserve verbatim so downstream processing can handle it.
if is_active():
out.append(m.group(0))
# trailing literal
if is_active():
out.append(text[pos:])
if stack:
raise ValueError("unclosed `if` block(s)")
return "".join(out)
def process(self, infile:str):
"""
Main calling point: preprocesses one file
"""
self.infile = infile
# Some options are the same between containers and pods; determine
# which description to use from the name of the source man page.
self.pod_or_container = 'container'
if '-pod-' in infile or '-kube-' in infile:
self.pod_or_container = 'pod'
# foo.md.in -> foo.md -- but always write to a tmpfile
outfile = os.path.splitext(infile)[0]
outfile_tmp = outfile + '.tmp.' + str(os.getpid())
with open(infile, 'r', encoding='utf-8') as fh_in, open(outfile_tmp, 'w', encoding='utf-8', newline='\n') as fh_out:View on GitHub (pinned to a2409076ef)
Solutions
- Add one '<< endif >>' per open '<< if >>' at the end of the block
- Check the closer's exact spelling: lowercase 'endif' with single spaces inside << >>
- grep -c '<< if ' and '<< endif >>' in the file and make the counts match
Example fix
# before << if is_quadlet >> **--pod**=... # after << if is_quadlet >> **--pod**=... << endif >>
Defensive patterns
Strategy: validation
Validate before calling
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`'
elif inner == 'endif':
assert stack > 0, f'{name}: `end` without `if`'
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
- The closer token is exactly '<< endif >>' — '<< end >>' and '<< ENDIF >>' are preserved verbatim and leave the block open
- grep-check balance before committing: counts of '<< if ' and '<< endif >>' must match per file
- Run the preprocessor locally (./hack/markdown-preprocess) before opening docs PRs; it is fast and catches this immediately
When it happens
Trigger: An options/*.md file ends with '<< if is_quadlet >>' ... and no '<< endif >>'; or the closer is misspelled ('<< end >>', '<< fi >>', '<<Endif>>'), so the stack never empties.
Common situations: Appending new conditional text at the bottom of a shared option file and forgetting the closer; renaming/reformatting tokens with an editor that changed case; block accidentally spanning past end of file during a merge conflict resolution.
Related errors
- `else` without `if`
- multiple `else` in the same `if`
- `end` without `if`
- 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/d8ab8ad6f616eca0.
Report an issue: GitHub.