apache/beam · error · ValueError
File " " is not a valid .py file.
Error message
File "{path}" is not a valid .py file. What it means
The Beam YAML MapToFields transform raises this when a Python UDF is specified via both `path` and `name` but the file path does not end with '.py'. The transform loads the script with PythonCallableWithSource.load_from_script and requires a .py extension as a sanity check.
Solutions
- Ensure the `path` points to a plain-text file ending in '.py' containing the callable named by `name`.
- Extract the function into a .py file if it currently lives in a notebook or module.
- Alternatively use the inline `expression` or `callable` config options instead of `path`.
Example fix
# before config: path: transforms/udf.pyc name: my_fn # after config: path: transforms/udf.py name: my_fn
Defensive patterns
Strategy: validation
Validate before calling
assert path.endswith('.py'), f'File "{path}" is not a valid .py file.' Type guard
def is_python_udf_spec(cfg: dict) -> bool:
return isinstance(cfg.get('path'), str) and cfg['path'].endswith('.py') and bool(cfg.get('name')) Try / catch
try:
out = run_pipeline(spec)
except ValueError as e:
if 'is not a valid .py file' in str(e):
spec['config']['path'] = spec['config']['path'] + '.py'
out = run_pipeline(spec)
else:
raise Prevention
- Reference only plain .py text files, never .pyc or notebooks
- Always pair `path` with `name` for Python UDFs
- Verify the file is committed/uploaded and readable by the worker
When it happens
Trigger: Calling _expand_python_mapping_func with {'path': '...', 'name': '...'} where path has a non-.py extension, e.g. pointing at a compiled .pyc, a .txt, a module directory, or an IPython notebook .ipynb.
Common situations: Users reference a packaged module, a notebook, a .pyc, or a file with a missing/wrong extension; also happens when copy-pasting config from a JavaScript example and forgetting to change the extension.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- File " " is not a valid .js file.
- Edge source and target cannot be empty
- HuggingFacePipelineModelHandler requires either 'task' or…
- Incompatible types: vs
- Missing config in ML transform spec
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/d5a62a37999b21c1.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/python/apache_beam/yaml/yaml_mapping.py:308
}}
}}
}}
return obj;
}}
function __wrapper__(row) {{
return {user_entrypoint}(__convert_dates__(row));
}}
"""
return _JsFunctionWrapper(source_code, '__wrapper__')
def _expand_python_mapping_func(
original_fields, expression=None, callable=None, path=None, name=None):
if path and name:
if not path.endswith('.py'):
raise ValueError(f'File "{path}" is not a valid .py file.')
py_file = FileSystems.open(path).read().decode()
return python_callable.PythonCallableWithSource.load_from_script(
py_file, name)
elif expression:
# TODO(robertwb): Consider constructing a single callable that takes
# the row and returns the new row, rather than invoking (and unpacking)
# for each field individually.
source = '\n'.join(['def fn(__row__):'] + [
f' {name} = __row__.{name}'
for name in original_fields if name in expression
] + [' return (' + expression + ')'])
else:
source = callable
return python_callable.PythonCallableWithSource(source)View on GitHub (pinned to 12126d8942)