[Bug]: Files starting with PACKAGE_NAME := ... misclassified as binary and skipped
What happened?
Summary
Cookiecutter incorrectly classifies certain plain text template files as binary when they start with:
PACKAGE_NAME := {{ cookiecutter.project_slug }}As a result, the file is copied without Jinja rendering, leaving template variables unresolved.
Expected Behavior
The file should be treated as text and rendered:
PACKAGE_NAME := example-packageActual Behavior
The file is treated as binary and copied as-is:
PACKAGE_NAME := {{ cookiecutter.project_slug }}No warning or error is emitted.
Root Cause
Cookiecutter uses the binaryornot library to determine whether a file is binary.
The file starts with:
PACKAGE_NAME := ...The first bytes are:
PACKbinaryornot includes b"PACK" in its binary signature list, so:
chunk.startswith(b"PACK") → TrueThis results in a false positive binary classification, causing Cookiecutter to skip rendering entirely.
Debug Evidence
from binaryornot.check import is_binary
print(is_binary("foo_file")) # Truefrom binaryornot.helpers import _BINARY_SIGNATURES
chunk = b'PACKAGE_NAME := {{ cookiecutter.project_slug }}\n'
for sig in _BINARY_SIGNATURES:
if chunk.startswith(sig):
print(sig)Output:
b'PACK'Workarounds
Any of the following avoids the issue:
- Add a blank line
PACKAGE_NAME := {{ cookiecutter.project_slug }}- Add a comment
# Generated by cookiecutter
PACKAGE_NAME := {{ cookiecutter.project_slug }}- Rename variable
PROJCT_NAME := {{ cookiecutter.project_slug }}Proposed Enhancement
Since binary detection is heuristic and can produce false positives, it would be useful to provide a way to override it.
Proposal
Add a configuration option similar to _copy_without_render, for example:
{
"_force_render": [
"Makefile",
"foo_file",
"*.mk"
]
}Suggested Behavior
- If path matches
_copy_without_render→ copy without rendering - If path matches
_force_render→ always render as text - Otherwise → use binary detection
Benefits
- Avoids fragile reliance on heuristics
- Gives template authors explicit control
- Solves real-world edge cases like this one
- Maintains backward compatibility
Impact
- Silent rendering failures
- Hard to debug without
--verbose - Affects common files (e.g., Makefile, config files)
- Any file starting with
PACK...may be impacted
Conclusion
This is a false positive in binary detection leading to skipped rendering. A configurable override would make Cookiecutter more robust and predictable.
Steps to reproduce
- Create a minimal template:
cookiecutter.json
{
"project_slug": "example-package"
}{{cookiecutter.project_slug}}/foo_file
PACKAGE_NAME := {{ cookiecutter.project_slug }}- Run:
cookiecutter --no-input /path/to/template- Inspect output:
cat example-package/foo_fileTemplate
cookiecutter.json
{
"project_slug": "example-package"
}Output / traceback
Cookiecutter version
2.7.1
Python version
3.12
Operating system
Linux
How did you install Cookiecutter?
uv
Additional context
No response
Source: cookiecutter/cookiecutter