python-poetry/poetry · error · ValueError
Bad script ({name}): script needs to specify a function with
Error message
Bad script ({name}): script needs to specify a function within a module like: module(.submodule):function
Instead got: {script_with_extras} What it means
Raised by EditableBuilder._build_scripts at src/poetry/masonry/builders/editable.py:163-179 when a script entry under [tool.poetry.scripts] does not split into exactly 'module' and 'callable' on ':'. The split raising ValueError ('not enough' = no colon, 'too many' = multiple colons) is caught and re-raised with guidance. Format must be module(.submodule):function.
Source
Thrown at src/poetry/masonry/builders/editable.py:179
script_without_extras = script_with_extras.split("[")[0]
try:
module, callable_ = script_without_extras.split(":")
except ValueError as exc:
msg = (
f"Bad script ({name}): script needs to specify a function within a"
" module like: module(.submodule):function\nInstead got:"
f" {script_with_extras}"
)
if "not enough values" in str(exc):
msg += (
"\nHint: If the script depends on module-level code, try"
" wrapping it in a main() function and modifying your script"
f' like:\n{name} = "{script_with_extras}:main"'
)
elif "too many values" in str(exc):
msg += '\nToo many ":" found!'
raise ValueError(msg)
callable_holder = callable_.split(".", 1)[0]
script_file = scripts_path.joinpath(name)
self._debug(
f" - Adding the <c2>{name}</c2> script to <b>{scripts_path}</b>"
)
with script_file.open("w", encoding="utf-8") as f:
f.write(
decode(
SCRIPT_TEMPLATE.format(
python=self._env.python,
module=module,
callable_holder=callable_holder,
callable_=callable_,
)
)
)View on GitHub (pinned to 92b74dcfe3)
Solutions
- Rewrite the entry as module:func, e.g. 'foo = "mypkg.cli:main"'.
- If the target is module-level code, wrap it in a main() function and point at ':main'.
- Remove extra colons; submodule dotted form goes before the single colon (mypkg.sub:func).
Example fix
# before [tool.poetry.scripts] foo = "mypkg" # no :function bar = "a:b:c" # too many colons # after [tool.poetry.scripts] foo = "mypkg:main" bar = "a.sub:run"
Defensive patterns
Strategy: validation
Validate before calling
import re
def validate_script_entry(script: str) -> None:
target = script.split('[')[0]
parts = target.split(':')
if len(parts) != 2 or not parts[0] or not parts[1]:
raise ValueError(
f'Bad script {script!r}; expected module(.submodule):function'
) Type guard
def is_valid_script(script: str) -> bool:
target = script.split('[')[0]
parts = target.split(':')
return len(parts) == 2 and bool(parts[0]) and bool(parts[1]) Try / catch
try:
builder._build_scripts(scripts)
except ValueError as e:
if 'Bad script' in str(e):
raise SystemExit(f'Fix [tool.poetry.scripts]: {e}') from e
raise Prevention
- Always write scripts as module:func (use dotted submodule before the colon).
- Lint the [tool.poetry.scripts] table in CI with a regex check.
When it happens
Trigger: Running `poetry install` (editable, on the current project) when [tool.poetry.scripts] has an entry like 'foo = "mymain"' (no ':function') or 'foo = "a:b:c"' (two colons). Build during editable install of the project.
Common situations: Copy-pasted a setuptools console_scripts entry that omits the function, pointed a script at a module rather than a callable, or accidentally used a Windows drive-letter colon.
Related errors
- Missing [url] in source {name!r}.
- Extra [{extra}] is not specified.
- pyproject.toml changed significantly since poetry.lock was l
- Setting {self.argument('key')} does not exist
- You can only pass one value.
AI-assisted analysis of python-poetry/poetry@92b74dcfe3 (2026-08-04).
Data as JSON: /data/errors/cc12624da9257bd0.json.
Report an issue: GitHub.