Muhammad Ridwan
05/13/2026, 3:36 AMMarvin
05/13/2026, 3:36 AMMarvin
05/13/2026, 3:39 AMstatus code: -11 usually means the flow process was killed by SIGSEGV (segmentation fault).
So the important distinction is:
- Prefect is only reporting that the process crashed
- the actual cause is usually lower-level than normal Python exceptions:
- native extension crash (numpy, pandas, pyarrow, ML libs, DB drivers, etc.)
- bad/broken binary dependency
- container/runtime-level memory issue
- less commonly, a Python interpreter / ctypes / C-extension issue
Prefect marks that run as Crashed and shows the generic message:
Process exited with an unexpected status code.
What to check first
1. Look at the infrastructure logs, not just Prefect logs
- Kubernetes: kubectl logs <pod> --previous
- Docker: docker logs <container>
- ECS/Cloud Run/etc.: check the platform logs/stderr
- Also check for messages like Segmentation fault, core dumped, or native library errors
2. Figure out whether it happens on import or during execution
- If the run dies immediately, it may be crashing while importing a library
- If it dies later, add log lines around suspicious code sections
3. Suspect native libraries first
Common offenders:
- numpy
- pandas
- pyarrow
- polars
- database drivers
- ML/LLM libraries
- anything using ctypes or compiled extensions
4. Check your execution environment
- Did a dependency version change recently?
- Did the base image change?
- Are you using Alpine? If so, binary compatibility can be an issue
- Any architecture mismatch (arm64 vs amd64)?
5. Try to reproduce outside Prefect
Run the same code directly in the same image / environment:
python your_flow_script.py
If it still exits with -11, it’s not really a Prefect problem — Prefect is just surfacing the crash.
Useful debugging approach
Add very explicit prints/logs to narrow it down:
python
from prefect import flow, get_run_logger
@flow
def my_flow():
logger = get_run_logger()
<http://logger.info|logger.info>("starting")
<http://logger.info|logger.info>("before import")
import pandas as pd
<http://logger.info|logger.info>("before read")
df = pd.read_parquet("some_file.parquet")
<http://logger.info|logger.info>("before transform")
result = df.groupby("x").size()
<http://logger.info|logger.info>("done")
return len(result)
If the last log is before read, then read_parquet or a dependency under it is the likely culprit.
Things that often fix it
- Pin dependency versions instead of floating latest versions
- Rebuild the environment from scratch
- Switch from python:alpine to python:slim if applicable
- Reinstall or downgrade the suspect binary package
- Verify system libs required by the package are present
- Check memory limits on the container/pod
Prefect-specific note
In Prefect 3.x, this message is basically a wrapper around the subprocess exit code. Prefect does not know the exact segfault reason from that line alone.
Relevant links
- Prefect repo: Prefect on GitHub
- There wasn’t an exact matching discussion for -11, but there is related crash-state work in the repo:
- process worker shutdown crashed-state fix
If you want, paste:
- how you’re running it (process worker, Docker worker, Kubernetes worker, etc.)
- the last ~30 lines before the crash
- your imports / libraries used in the flow
and I can help narrow down the likely source.Muhammad Ridwan
05/13/2026, 3:45 AMMarvin
05/13/2026, 3:45 AMMarvin
05/13/2026, 3:45 AMpandas
- pyarrow
- fastparquet
- polars
- compression libs (zstd, snappy, gzip bindings)
- S3 client stack
- boto3 / botocore usually won’t segfault by themselves, but downstream file handling libraries can
- HTTP response handling
- especially if you stream large responses into native parsers
- memory pressure
- large downloads, decompression, parquet/arrow decoding can trigger hard crashes in native libs
A normal Python exception from HTTP/S3 would usually show up in logs. -11 suggests something underneath Python is blowing up.
What I’d do next
1. Split ingestion steps with precise logging
Add logs before and after every boundary:
from prefect import flow, get_run_logger
@flow
def ingest():
logger = get_run_logger()
<http://logger.info|logger.info>("starting http fetch")
data = fetch_http()
<http://logger.info|logger.info>("finished http fetch")
<http://logger.info|logger.info>("starting s3 fetch")
obj = fetch_s3()
<http://logger.info|logger.info>("finished s3 fetch")
<http://logger.info|logger.info>("starting parse")
parsed = parse_data(obj)
<http://logger.info|logger.info>("finished parse")
<http://logger.info|logger.info>("starting transform")
transform(parsed)
<http://logger.info|logger.info>("finished transform")
The last emitted line is your best clue.
2. Separate download from parse
For example, if you do:
- HTTP/S3 read
- immediately read_parquet, read_csv, json_normalize, decompression, etc.
then split them:
- download bytes to disk
- log file size
- parse in a separate step
That tells you whether the crash is network/client-side or parser-side.
3. Watch memory usage
If this is in a container/pod, check:
- pod/container memory limits
- RSS usage before parse/decompression
- whether the files are much larger after decompression
Even though OOM often appears as 137, memory stress can still surface as native crashes in downstream libraries.
4. Test each source path independently
Run:
- only HTTP ingestion
- only S3 ingestion
- same code path with tiny files
- same code path with the problematic real file
If one specific file or format causes it, that strongly points to parser/native-lib issues.
5. Suspect file format handlers
Especially if you ingest:
- parquet
- feather/arrow
- ORC
- compressed CSV/JSON
- Excel via engine libs
If you tell me the exact read calls (pd.read_parquet, pl.read_parquet, pyarrow.parquet.read_table, etc.), I can suggest more targeted checks.
Very common pattern
A lot of these -11 cases turn out to be:
- corrupted parquet/arrow file
- incompatible pyarrow build
- bad compression codec interaction
- huge response loaded fully into memory, then parsed
High-signal experiments
Try these one at a time:
- write payload to disk without parsing
- if that works, parsing is likely the issue
- parse a very small known-good sample
- if that works, size/content matters
- upgrade or pin parser libs
- especially pyarrow, pandas, polars
- avoid in-memory bytes parsing temporarily
- parse from local file instead
Example pattern:
python
import tempfile
from prefect import flow, get_run_logger
@flow
def ingest():
logger = get_run_logger()
<http://logger.info|logger.info>("downloading from s3")
body = get_s3_bytes()
<http://logger.info|logger.info>(f"downloaded {len(body)} bytes")
with tempfile.NamedTemporaryFile(delete=False, suffix=".parquet") as f:
f.write(body)
path = f.name
<http://logger.info|logger.info>(f"wrote temp file to {path}")
<http://logger.info|logger.info>("about to parse parquet")
df = read_parquet_file(path)
<http://logger.info|logger.info>(f"parsed rows={len(df)}")
If it dies at about to parse parquet, that’s a strong signal.
Most useful info you could share next
Please paste:
- the exact ingestion calls you’re makingMarvin
05/13/2026, 3:45 AMrequests.get(...).content
- boto3.client("s3").get_object(...)
- pd.read_parquet(...)
- pl.read_csv(...)
- file formats involved
- whether this runs in Docker/Kubernetes/process worker
- the last few log lines before the crash
Then I can help you isolate the most likely failing layer.Muhammad Ridwan
05/13/2026, 3:51 AMMarvin
05/13/2026, 3:51 AMMarvin
05/13/2026, 3:51 AMnetCDF4 / HDF5 native libraries
- h5py
- xarray engine underneath
- `libcurl`/OpenDAP-related native behavior depending on how the file is accessed
- mixed binary dependency issues in the container
Even with memory below 3.5 GB, -11 still fits a native library segfault much better than a resource-limit kill.
Why this pattern is suspicious
- NetCDF/HDF5 readers are backed by C libraries
- byte-range / partial reads can exercise edge cases in remote-file handling
- ERA5 via cdsapi may download fine, but opening/decoding the resulting files often touches native code
- if HTTP and S3 both trigger it for HYCOM, the common layer may be the NetCDF parser/engine, not the transport
What I would test next
1. Identify the exact open/read engine
Please check whether you are using:
- xarray.open_dataset(...)
- xarray.open_mfdataset(...)
- netCDF4.Dataset(...)
- h5netcdf
- scipy engine
This matters a lot because different engines hit different native libraries.
2. Force a different xarray engine
If you’re using xarray, try explicitly switching engines.
For example:
python
import xarray as xr
ds = xr.open_dataset(path, engine="h5netcdf")
or
python
import xarray as xr
ds = xr.open_dataset(path, engine="netcdf4")
If one crashes and the other doesn’t, you’ve isolated the layer.
3. Download first, then open locally
Do not combine remote access and parsing in one step for debugging.
Instead:
- fetch the file or byte-ranged content
- save it to local disk
- open it in a separate step
That distinguishes:
- transport issue
from
- parser / file-content issue
4. Check whether the byte-ranged object is actually a valid standalone NetCDF file
This is a big one. A byte range from a NetCDF/HDF5-backed file may not be a valid self-contained file unless you know exactly what bytes are needed. If you hand partial content to a library expecting a complete file, behavior may range from a clean exception to a native crash depending on the library stack.
5. Try a pure local known-good sample
Open:
- a tiny known-good NetCDF from local disk
- then the problematic HYCOM sample
- then the ERA5 sample
If only one dataset/source crashes, that narrows it to file structure/content.
6. Log the exact line before the crash
For example:
python
<http://logger.info|logger.info>("before open_dataset")
ds = xr.open_dataset(local_path, engine="netcdf4")
<http://logger.info|logger.info>("after open_dataset")
<http://logger.info|logger.info>("before load")
ds.load()
<http://logger.info|logger.info>("after load")
Important distinction:
- crash on open_dataset -> engine/native open
- crash on .load() -> actual data decode/read
- crash on slicing/resampling -> later compute path
What I suspect most strongly from your description
If you are doing byte-ranged HYCOM NetCDF:
- a partial file may be getting passed into a library that expects a complete NetCDF/HDF5 container
- HDF5-backed formats in particular are not generally friendly to arbitrary partial-byte local reconstruction
- this can expose segfaults in lower-level libs depending on versions
If you are using xarray with netcdf4, try:
- engine="h5netcdf"
and vice versa.
Container-specific checks
Inside the container, I’d verify versions of:
- xarray
- netCDF4
- h5py
- h5netcdf
- numpy
A mismatched native stack can absolutely produce this.
You can print them at runtime:
python
import xarray as xr
import numpy as np
import netCDF4
import h5py
import h5netcdf
print("xarray", xr.__version__)
print("numpy", np.__version__)
print("netCDF4", netCDF4.__version__)
print("h5py", h5py.__version__)
print("h5netcdf", h5netcdf.__version__)
High-value experiments
In order, I’d run these:
1. Open a fully downloaded local file
2. Switch xarray engineMarvin
05/13/2026, 3:51 AMopen_dataset vs load() separately
My current hypothesis ranking
1. partial/corrupt NetCDF content being passed to native parser
2. netCDF4 / HDF5 binary-library crash
3. engine-specific bug (netcdf4 vs h5netcdf)
4. less likely: transport/client issue
5. unlikely: Prefect itself
If you share the exact code you use to open the HYCOM and ERA5 data, I can tell you which line is most likely causing the segfault and suggest the safest alternative.