Skip to content

(Actual) random crashes reading empty aggregated array parameter (ProxyList) via getDoubleArrayItem #76

Description

@hannahlanzrath

Update:

Jo cannot reproduce the issue, I created a fresh env and still face the same issue.


I ran into a non-deterministic crash when using particle_reaction_model on a LumpedRateModelWithoutPores unit (bulk_reaction_model is not supported) for a unit without a solid phase. The exact same code, run repeatedly with no changes, sometimes succeeds and sometimes fails with:

CADETProcess.CADETProcessError.CADETProcessError: CADET Error: Simulation failed with Error (runSimulation:416) Simulation failed: Retrieving double parameter MAL_KFWD_SOLID failed

Root cause

Assigning a normal bulk MassActionLaw reaction to particle_reaction_model triggers CADET-Process auto-cast to a particle reaction. Since this unit has no solid phase, the solid-phase reaction parameters end up empty which is correctly represented as CADET-Process's own ProxyList container.

In CADET-python theparam_provider_num_elements (cadet/cadet_dll_utils.py) only recognizes list and numpy.ndarray as sized containers:

if isinstance(o, list):
    return len(o)
elif isinstance(o, np.ndarray):
    return o.size
return 1   # falls through here for ProxyList, even when empty

So it reports length 1 for an empty array, CADET-Core asks for index 0, and param_provider_get_double_array_item raises an unhandled IndexError on float(o[index]). That exception escapes the ctypes callback uncaught . Ctypes prints "Exception ignored..." and the output pointer (val[0]) is never written, so whatever uninitialized memory happens to be there gets read as if it were a valid value. Which probably explains the randomness?

Why this used to work: before CADET-Process's d8c6669 ("Add ProxyList/Array to allow indexed modification of aggregated properties", 2025-01-29, in every release since 0.10.1), an empty aggregated reaction array resolved to None and was dropped from the config entirely, so CADET-Core never asked for it at all. I confirmed this directly on CADET-Process 0.10.1 the identical reproducer succeeds 10/10 fresh CADET-Process runs; on every version since the ProxyList change, it fails 30-60% of the time, also reproducing identically with CADET-Process 0.11.0, 0.11.1, and 0.12.0(dev), independent of numpy version. So this is a CADET-python bug exposed by a CADET-Process feature change.

Suggested fix: in param_provider_get_double_array_item, catch IndexError/TypeError around o[index] and write a defined value instead of leaving val unset. Also worth making param_provider_num_elements recognize any object with __len__, not just list/np.ndarray.

Environment: CADET-Process 0.12.0 (also 0.11.0/0.11.1), CADET-python 1.2.0, CADET-Core (cadet conda package) 5.1.1.


MRE

This builds a 3-unit flow sheet, runs it in 10 fresh subprocesses, shows the failure rate, then shows a 3-line patch (catching the IndexError and writing a defined 0.0).

mre_particle_reaction_no_pores_uninitialized_value.py

import ctypes
import subprocess
import sys
import textwrap
import warnings


REPRODUCER_SCRIPT = textwrap.dedent("""
    import warnings
    from CADETProcess.processModel import (
        ComponentSystem, Inlet, Outlet, LumpedRateModelWithoutPores,
        MassActionLaw, FlowSheet, Process
    )
    from CADETProcess.simulator import Cadet

    component_system = ComponentSystem(1)
    inlet = Inlet(component_system, name='inlet')
    column = LumpedRateModelWithoutPores(component_system, name='column')
    outlet = Outlet(component_system, name='outlet')

    reaction_system = MassActionLaw(component_system)
    reaction_system.add_reaction(indices=[0], coefficients=[-1], k_fwd=1e-3, k_bwd=0)

    with warnings.catch_warnings():
        warnings.simplefilter("ignore")
        # column has no pores/bound phase, but supports_particle_reaction is True,
        # so this is the documented way to attach a reaction to it -- and it is
        # silently cast: bulk reaction -> particle reaction.
        column.particle_reaction_model = reaction_system

    flow_sheet = FlowSheet(component_system)
    flow_sheet.add_unit(inlet)
    flow_sheet.add_unit(column)
    flow_sheet.add_unit(outlet)
    flow_sheet.add_connection(inlet, column)
    flow_sheet.add_connection(column, outlet)

    process = Process(flow_sheet, 'mre')
    column.length = 0.1
    column.diameter = 0.01
    column.axial_dispersion = 1e-7
    column.total_porosity = 1
    column.discretization.ncol = 20

    inlet.flow_rate = [1e-6, 0, 0, 0]
    process.cycle_time = 100
    _ = process.add_event('start', 'flow_sheet.inlet.c', [1.0], 0)
    _ = process.add_event('stop', 'flow_sheet.inlet.c', [0.0], 10)

    simulator = Cadet()
    simulator.use_dll = True
    with warnings.catch_warnings():
        warnings.simplefilter("ignore")
        simulator.simulate(process)
    print("SUCCESS")
""")

# The exact same script, with the 3-line fix injected before anything else runs:
# catch the IndexError on the empty solid-phase array and write a defined value
# (0.0 -- the physically correct rate for a reaction phase that does not exist)
# instead of leaving the output pointer uninitialized.
PATCH_PREAMBLE = textwrap.dedent("""
    import ctypes
    import cadet.cadet_dll_utils as cdu

    def _patched_get_double_array_item(reader, name, index, val):
        n = name.decode('utf-8')
        c = reader.current()
        if n not in c:
            return -1
        o = c[n]
        try:
            float_val = float(o)
        except TypeError:
            try:
                float_val = float(o[index])
            except IndexError:
                val[0] = ctypes.c_double(0.0)
                return 0
        val[0] = ctypes.c_double(float_val)
        return 0

    cdu.param_provider_get_double_array_item = _patched_get_double_array_item
""")


def run_fresh_process(script: str) -> str:
    """Run `script` in a brand new Python process; return 'success' or the error."""
    result = subprocess.run(
        [sys.executable, "-c", script],
        capture_output=True, text=True,
    )
    if "SUCCESS" in result.stdout:
        return "success"
    stderr_lines = [line for line in result.stderr.strip().splitlines() if line.strip()]
    return f"FAILED: {stderr_lines[-1] if stderr_lines else '(no stderr)'}"


def main() -> None:
    n_runs = 10

    print(f"Running the unpatched reproducer in {n_runs} fresh processes...")
    outcomes = [run_fresh_process(REPRODUCER_SCRIPT) for _ in range(n_runs)]
    for i, outcome in enumerate(outcomes):
        print(f"  run {i}: {outcome}")
    n_failed = sum(1 for o in outcomes if o != "success")
    print(f"{n_failed}/{n_runs} fresh-process runs failed -- with the exact same "
          f"code and environment every time.\n")

    print(f"Running the patched reproducer in {n_runs} fresh processes...")
    outcomes_patched = [
        run_fresh_process(PATCH_PREAMBLE + REPRODUCER_SCRIPT) for _ in range(n_runs)
    ]
    for i, outcome in enumerate(outcomes_patched):
        print(f"  run {i}: {outcome}")
    n_failed_patched = sum(1 for o in outcomes_patched if o != "success")
    print(f"{n_failed_patched}/{n_runs} fresh-process runs failed after the patch.")


if __name__ == "__main__":
    main()


All packages

# Name                    Version                   Build  Channel
_openmp_mutex             4.5                      20_gnu    conda-forge
_x86_64-microarch-level   3                   3_x86_64_v3    conda-forge
about-time                4.2.1                    pypi_0    pypi
addict                    2.3.0                    pypi_0    pypi
alive-progress            3.3.0                    pypi_0    pypi
anyio                     4.14.0                   pypi_0    pypi
argon2-cffi               25.1.0                   pypi_0    pypi
argon2-cffi-bindings      25.1.0                   pypi_0    pypi
arrow                     1.4.0                    pypi_0    pypi
arviz                     1.2.0                    pypi_0    pypi
arviz-base                1.2.0                    pypi_0    pypi
arviz-plots               1.2.0                    pypi_0    pypi
arviz-stats               1.2.0                    pypi_0    pypi
asttokens                 3.0.1                    pypi_0    pypi
async-lru                 2.3.0                    pypi_0    pypi
attrs                     26.1.0                   pypi_0    pypi
autograd                  1.8.0                    pypi_0    pypi
aws-c-auth                0.10.3               hea842a7_2    conda-forge
aws-c-cal                 0.9.14               h78948cc_2    conda-forge
aws-c-common              0.14.0               hb03c661_0    conda-forge
aws-c-compression         0.3.2                haa0cbde_2    conda-forge
aws-c-http                0.11.0               h6488f85_2    conda-forge
aws-c-io                  0.26.3               h3bf836e_5    conda-forge
aws-c-s3                  0.12.5               hb916526_1    conda-forge
aws-c-sdkutils            0.2.4                haa0cbde_6    conda-forge
aws-checksums             0.2.10               haa0cbde_2    conda-forge
babel                     2.18.0                   pypi_0    pypi
beautifulsoup4            4.15.0                   pypi_0    pypi
bleach                    6.4.0                    pypi_0    pypi
bzip2                     1.0.8                hda65f42_9    conda-forge
c-ares                    1.34.6               hb03c661_0    conda-forge
ca-certificates           2026.6.17            hbd8a1cb_0    conda-forge
cadet                     5.1.1                h56c1e75_1    conda-forge
cadet-process             0.12.0                   pypi_0    pypi
cadet-python              1.2.0                    pypi_0    pypi
certifi                   2026.5.20                pypi_0    pypi
cffi                      2.0.0                    pypi_0    pypi
charset-normalizer        3.4.7                    pypi_0    pypi
cloudpickle               3.1.2              pyhcf101f3_1    conda-forge
cma                       4.4.4                    pypi_0    pypi
comm                      0.2.3                    pypi_0    pypi
contourpy                 1.3.3                    pypi_0    pypi
corner                    2.2.3                    pypi_0    pypi
cycler                    0.12.1                   pypi_0    pypi
debugpy                   1.8.21                   pypi_0    pypi
decorator                 5.3.1                    pypi_0    pypi
defusedxml                0.7.1                    pypi_0    pypi
deprecated                1.3.1                    pypi_0    pypi
dill                      0.4.1                    pypi_0    pypi
diskcache                 5.6.3                    pypi_0    pypi
et-xmlfile                2.0.0                    pypi_0    pypi
executing                 2.2.1                    pypi_0    pypi
fastjsonschema            2.21.2                   pypi_0    pypi
filelock                  3.29.4                   pypi_0    pypi
fonttools                 4.63.0                   pypi_0    pypi
fqdn                      1.5.1                    pypi_0    pypi
gmp                       6.3.0                hac33072_2    conda-forge
graphemeu                 0.7.2                    pypi_0    pypi
h11                       0.16.0                   pypi_0    pypi
h5py                      3.16.0                   pypi_0    pypi
hdf5                      2.1.0           nompi_h735b18d_107    conda-forge
hopsy                     1.7.0                    pypi_0    pypi
httpcore                  1.0.9                    pypi_0    pypi
httpx                     0.28.1                   pypi_0    pypi
icu                       78.3                 h33c6efd_0    conda-forge
idna                      3.18                     pypi_0    pypi
ipykernel                 7.3.0                    pypi_0    pypi
ipython                   9.14.1                   pypi_0    pypi
ipython-pygments-lexers   1.1.1                    pypi_0    pypi
ipywidgets                8.1.8                    pypi_0    pypi
isoduration               20.11.0                  pypi_0    pypi
jedi                      0.20.0                   pypi_0    pypi
jinja2                    3.1.6                    pypi_0    pypi
joblib                    1.5.3                    pypi_0    pypi
json5                     0.14.0                   pypi_0    pypi
jsonpointer               3.1.1                    pypi_0    pypi
jsonschema                4.26.0                   pypi_0    pypi
jsonschema-specifications 2025.9.1                 pypi_0    pypi
jupyter                   1.1.1                    pypi_0    pypi
jupyter-client            8.9.1                    pypi_0    pypi
jupyter-console           6.6.3                    pypi_0    pypi
jupyter-core              5.9.1                    pypi_0    pypi
jupyter-events            0.12.1                   pypi_0    pypi
jupyter-lsp               2.3.1                    pypi_0    pypi
jupyter-server            2.19.0                   pypi_0    pypi
jupyter-server-terminals  0.5.4                    pypi_0    pypi
jupyterlab                4.5.8                    pypi_0    pypi
jupyterlab-pygments       0.3.0                    pypi_0    pypi
jupyterlab-server         2.28.0                   pypi_0    pypi
jupyterlab-widgets        3.0.16                   pypi_0    pypi
keyutils                  1.6.3                hb9d3cd8_0    conda-forge
kiwisolver                1.5.0                    pypi_0    pypi
krb5                      1.22.2               ha1258a1_0    conda-forge
lark                      1.3.1                    pypi_0    pypi
lazy-loader               0.5                      pypi_0    pypi
ld_impl_linux-64          2.45.1          default_hbd61a6d_102    conda-forge
libaec                    1.1.5                h088129d_0    conda-forge
libamd                    3.3.3           haaf9dc3_7100102    conda-forge
libblas                   3.11.0          8_h4a7cf45_openblas    conda-forge
libbtf                    2.3.2           h32481e8_7100102    conda-forge
libcamd                   3.3.3           h32481e8_7100102    conda-forge
libcblas                  3.11.0          8_h0358290_openblas    conda-forge
libccolamd                3.3.4           h32481e8_7100102    conda-forge
libcholmod                5.3.1           h59ddab4_7100102    conda-forge
libcolamd                 3.3.4           h32481e8_7100102    conda-forge
libcurl                   8.20.0               hcf29cc6_0    conda-forge
libcxsparse               4.4.1           h32481e8_7100102    conda-forge
libedit                   3.1.20250104    pl5321h7949ede_0    conda-forge
libev                     4.33                 hd590300_2    conda-forge
libexpat                  2.8.1                hecca717_1    conda-forge
libffi                    3.5.2                h3435931_0    conda-forge
libgcc                    15.2.0              he0feb66_19    conda-forge
libgcc-ng                 15.2.0              h69a702a_19    conda-forge
libgfortran               15.2.0              h69a702a_19    conda-forge
libgfortran5              15.2.0              h68bc16d_19    conda-forge
libgomp                   15.2.0              he0feb66_19    conda-forge
libhwloc                  2.13.0          default_he001693_1000    conda-forge
libiconv                  1.18                 h3b78370_2    conda-forge
libklu                    2.3.5           hf24d653_7100102    conda-forge
liblapack                 3.11.0          8_h47877c9_openblas    conda-forge
libldl                    3.3.2           h32481e8_7100102    conda-forge
liblzma                   5.8.3                hb03c661_0    conda-forge
libnghttp2                1.68.1               h877daf1_0    conda-forge
libnsl                    2.0.1                hb9d3cd8_1    conda-forge
libopenblas               0.3.33          pthreads_h94d23a6_0    conda-forge
libparu                   1.0.0           h17147ab_7100102    conda-forge
librbio                   4.3.4           h32481e8_7100102    conda-forge
libspex                   3.2.3           had10066_7100102    conda-forge
libspqr                   4.3.4           h852d39f_7100102    conda-forge
libsqlite                 3.53.2               h0c1763c_0    conda-forge
libssh2                   1.11.1               hcf80075_0    conda-forge
libstdcxx                 15.2.0              h934c35e_19    conda-forge
libstdcxx-ng              15.2.0              hdf11a46_19    conda-forge
libsuitesparseconfig      7.10.1          h92d6892_7100102    conda-forge
libumfpack                6.3.5           heb53515_7100102    conda-forge
libuuid                   2.42.2               h5347b49_0    conda-forge
libxcrypt                 4.4.36               hd590300_1    conda-forge
libxml2                   2.15.3               h49c6c72_0    conda-forge
libxml2-16                2.15.3               hca6bf5a_0    conda-forge
libzlib                   1.3.2                h25fd6f3_2    conda-forge
llvmlite                  0.47.0                   pypi_0    pypi
markupsafe                3.0.3                    pypi_0    pypi
matplotlib                3.11.0                   pypi_0    pypi
matplotlib-inline         0.2.2                    pypi_0    pypi
metis                     5.1.0             hd0bcaf9_1007    conda-forge
mistune                   3.2.1                    pypi_0    pypi
moocore                   0.3.1                    pypi_0    pypi
mpfr                      4.2.2                he0a73b1_0    conda-forge
mpmath                    1.3.0                    pypi_0    pypi
multiprocess              0.70.19                  pypi_0    pypi
narwhals                  2.22.1                   pypi_0    pypi
nbclient                  0.11.0                   pypi_0    pypi
nbconvert                 7.17.1                   pypi_0    pypi
nbformat                  5.10.4                   pypi_0    pypi
ncurses                   6.6                  hdb14827_0    conda-forge
nest-asyncio2             1.7.2                    pypi_0    pypi
networkx                  3.6.1              pyhcf101f3_0    conda-forge
notebook                  7.5.7                    pypi_0    pypi
notebook-shim             0.2.4                    pypi_0    pypi
numba                     0.65.1                   pypi_0    pypi
numpy                     2.4.6                    pypi_0    pypi
openpyxl                  3.1.5                    pypi_0    pypi
openssl                   3.6.3                h35e630c_0    conda-forge
optlang                   1.9.1                    pypi_0    pypi
packaging                 26.2               pyhc364b38_0    conda-forge
pandas                    3.0.3                    pypi_0    pypi
pandocfilters             1.5.1                    pypi_0    pypi
parso                     0.8.7                    pypi_0    pypi
pathos                    0.3.5                    pypi_0    pypi
pexpect                   4.9.0                    pypi_0    pypi
pillow                    12.2.0                   pypi_0    pypi
pip                       26.1.2             pyh8b19718_0    conda-forge
pipefunc                  0.93.0             pyhc364b38_0    conda-forge
platformdirs              4.10.0                   pypi_0    pypi
polyround                 0.4.0                    pypi_0    pypi
pox                       0.3.7                    pypi_0    pypi
ppft                      1.7.8                    pypi_0    pypi
prometheus-client         0.25.0                   pypi_0    pypi
prompt-toolkit            3.0.52                   pypi_0    pypi
psutil                    7.2.2           py312h5253ce2_0    conda-forge
ptyprocess                0.7.0                    pypi_0    pypi
pure-eval                 0.2.3                    pypi_0    pypi
pycparser                 3.0                      pypi_0    pypi
pygments                  2.20.0                   pypi_0    pypi
pymoo                     0.6.1.6                  pypi_0    pypi
pyparsing                 3.3.2                    pypi_0    pypi
python                    3.12.13         hd63d673_0_cpython    conda-forge
python-dateutil           2.9.0.post0              pypi_0    pypi
python-json-logger        4.1.0                    pypi_0    pypi
python_abi                3.12                    8_cp312    conda-forge
pyyaml                    6.0.3                    pypi_0    pypi
pyzmq                     27.1.0                   pypi_0    pypi
readline                  8.3                  h853b02a_0    conda-forge
referencing               0.37.0                   pypi_0    pypi
requests                  2.34.2                   pypi_0    pypi
rfc3339-validator         0.1.4                    pypi_0    pypi
rfc3986-validator         0.1.1                    pypi_0    pypi
rfc3987-syntax            1.1.0                    pypi_0    pypi
rpds-py                   2026.5.1                 pypi_0    pypi
s2n                       1.7.4                h92489ea_1    conda-forge
scikit-learn              1.9.0                    pypi_0    pypi
scipy                     1.17.1                   pypi_0    pypi
seaborn                   0.13.2                   pypi_0    pypi
send2trash                2.1.0                    pypi_0    pypi
setuptools                82.0.1             pyh332efcf_0    conda-forge
six                       1.17.0                   pypi_0    pypi
soupsieve                 2.8.4                    pypi_0    pypi
stack-data                0.6.3                    pypi_0    pypi
suitesparse               7.10.1          ha0f6916_7100102    conda-forge
superlu                   7.0.1                h8f6e6c4_0    conda-forge
swiglpk                   5.0.13                   pypi_0    pypi
sympy                     1.14.0                   pypi_0    pypi
tbb                       2023.0.0             hab88423_2    conda-forge
tbb-devel                 2023.0.0             hab88423_2    conda-forge
terminado                 0.18.1                   pypi_0    pypi
threadpoolctl             3.6.0                    pypi_0    pypi
tinycss2                  1.5.1                    pypi_0    pypi
tk                        8.6.13          noxft_h366c992_103    conda-forge
tornado                   6.5.7                    pypi_0    pypi
tqdm                      4.68.3                   pypi_0    pypi
traitlets                 5.15.1                   pypi_0    pypi
typing-extensions         4.15.0                   pypi_0    pypi
tzdata                    2026.2                   pypi_0    pypi
uri-template              1.3.0                    pypi_0    pypi
urllib3                   2.7.0                    pypi_0    pypi
wcwidth                   0.8.1                    pypi_0    pypi
webcolors                 25.10.0                  pypi_0    pypi
webencodings              0.5.1                    pypi_0    pypi
websocket-client          1.9.0                    pypi_0    pypi
wheel                     0.47.0             pyhd8ed1ab_0    conda-forge
widgetsnbextension        4.0.15                   pypi_0    pypi
wrapt                     2.2.1                    pypi_0    pypi
xarray                    2026.4.0                 pypi_0    pypi
xarray-einstats           0.10.0                   pypi_0    pypi
zstd                      1.5.7                hb78ec9c_6    conda-forge

Metadata

Metadata

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions