{"record":{"id":"2d8e291158b98142","repo":"podman-container-tools/podman","slug":"undefined-variable-name","errorCode":null,"errorMessage":"undefined variable: {name}","messagePattern":"undefined variable: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"hack/markdown-preprocess","lineNumber":58,"sourceCode":"\n        << \"foo\" if variable else \"bar\" >>\n        ```\n\n        Returns the rendered text.\n        \"\"\"\n        # Match << ... >>\n        TOK = re.compile(r\"<<(.*?)>>\", re.DOTALL)\n        out = []\n        pos = 0\n        stack = []  # each frame: {\"active\": bool, \"seen_else\": bool}\n\n        def is_active():\n            return all(f[\"active\"] for f in stack)\n\n        def get_variable(name: str):\n            v = context.get(name, None)\n            if v is None:\n                raise ValueError(f\"undefined variable: {name}\")\n            return v\n\n        def truthy(name: str) -> bool:\n            name = name.strip()\n            if name.startswith(\"not \"):\n                v = get_variable(name[4:].strip())\n                return not bool(v)\n            return bool(get_variable(name))\n\n        for m in TOK.finditer(text):\n            # write literal up to token\n            literal = text[pos:m.start()]\n            if is_active():\n                out.append(literal)\n            pos = m.end()\n\n            inner = m.group(1).strip()\n","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/podman-container-tools/podman/blob/a2409076ef2fef60ad9ac046375dedc7d9410ef4/hack/markdown-preprocess#L40-L76","documentation":"Raised by Preprocessor.render() when a conditional token references a name that is not a key of the context dict. The context is built in insert_file (hack/markdown-preprocess:206) and currently contains exactly one variable: {\"is_quadlet\": bool}. So inside docs/source/markdown/options/*.md the only valid conditions are 'is_quadlet' and 'not is_quadlet'; any other name in << if VAR >>, << if not VAR >>, or an inline '<<X if VAR else Y>>' raises this ValueError. Note the whole render runs inside process()'s per-line try, so it usually surfaces wrapped as \"Error while processing ... line '@@option foo'\" with this message as __cause__.","triggerScenarios":"An options/*.md file (included via @@option from a *.md.in man page) contains e.g. '<< if quadlet >>' instead of '<< if is_quadlet >>', or an inline token like '<< \"yes\" if enabled else \"no\" >>' where 'enabled' is not a context key. get_variable() finds context.get(name, None) is None and raises.","commonSituations":"Doc authors inventing a new variable name (quadlet, pod, remote) without extending the context dict in insert_file; copy-pasting Jinja-style conditionals from other docs; renaming is_quadlet and missing occurrences in shared option files (which are reused across many man pages).","solutions":["Rename the variable in the .md option file to 'is_quadlet' (or 'not is_quadlet')","If a genuinely new variable is needed, add it to the context dict in insert_file(): self.render(fh_included.read(), {\"is_quadlet\": is_quadlet, \"myvar\": value})","Read the __cause__ of the wrapping 'Error while processing {infile} line' exception to find which option file and line contain the bad token","grep the options dir for the bad name: grep -rn '<< if ' docs/source/markdown/options/"],"exampleFix":"# docs/source/markdown/options/pod-create.md (before)\n<< if quadlet >>**--pod**=...<< endif >>\n\n# after\n<< if is_quadlet >>**--pod**=...<< endif >>","handlingStrategy":"validation","validationCode":"# Lint option files before running the preprocessor\nimport re, pathlib, sys\nALLOWED = {'is_quadlet'}\nTOK = re.compile(r'<<(.*?)>>', re.DOTALL)\nbad = []\nfor p in pathlib.Path('docs/source/markdown/options').glob('*.md'):\n    for m in TOK.finditer(p.read_text()):\n        inner = m.group(1).strip()\n        cond = None\n        if inner.startswith('if ') and len(inner[3:].split()) in (1, 2):\n            cond = inner[3:].strip()\n        elif ' if ' in inner and ' else ' in inner:\n            _, rest = inner.split(' if ', 1)\n            cond = rest.split(' else ', 1)[0].strip()\n        if cond is not None:\n            var = cond[4:].strip() if cond.startswith('not ') else cond\n            if var not in ALLOWED:\n                bad.append(f'{p}: undefined variable {var!r}')\nif bad:\n    sys.exit('\\n'.join(bad))","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat 'is_quadlet' as the only documented render variable; extend insert_file()'s context dict whenever a new one is introduced and note it in the option-file header comment","Run the lint above in CI before make docs so bad tokens fail with file/variable names instead of the wrapped per-line error","Search before inventing: grep -rn '<< if ' docs/source/markdown/options/ to see the established variable vocabulary"],"tags":["markdown","docs","preprocessor","templating"],"backgroundTag":null,"analyzedSha":"a2409076ef2fef60ad9ac046375dedc7d9410ef4","analyzedAt":"2026-08-15T15:57:05.625Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}