ZhuLinsen/daily_stock_analysis · error · RuntimeError

{call_name} 调用进程未返回结果

Error message

{call_name} 调用进程未返回结果

What it means

RuntimeError raised when the akshare worker process died without sending anything back: parent_conn.recv() hits EOFError because the child closed the pipe (crashed, was OOM-killed, or segfaulted inside a native dependency) before delivering the (ok, value) result. It is distinct from the timeout case — the child ended, it didn't stall.

Source

Thrown at data_provider/akshare_fetcher.py:355

    process = ctx.Process(
        target=_akshare_timeout_worker,
        args=(child_conn, func, args, kwargs),
        name=f"akshare-{call_name}",
        daemon=True,
    )

    process.start()
    child_conn.close()

    try:
        if not parent_conn.poll(wait_seconds):
            _terminate_akshare_process(process)
            raise TimeoutError(f"{call_name} 调用超过 {wait_seconds:g}s,已放弃等待")

        try:
            ok, value = parent_conn.recv()
        except EOFError as exc:
            raise RuntimeError(f"{call_name} 调用进程未返回结果") from exc
    finally:
        parent_conn.close()
        process.join(_AKSHARE_TIMEOUT_PROCESS_JOIN_GRACE)
        _terminate_akshare_process(process)

    if ok:
        return value
    raise value


def _akshare_timeout_worker(conn, func, args, kwargs) -> None:
    try:
        conn.send((True, func(*args, **kwargs)))
    except BaseException as exc:
        try:
            conn.send((False, exc))
        except BaseException:
            try:

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Check dmesg/container logs for OOM kills of the 'akshare-*' child process; raise the memory limit or narrow the date range.
  2. Reinstall akshare, pandas and numpy so their binary versions are compatible (pip install --force-reinstall akshare).
  3. Retry once — transient native crashes do happen under load.
  4. If persistent for one symbol, that call likely crashes deterministically; test the akshare function standalone in a REPL to isolate it.
  5. Let the data-provider fallback chain switch to an alternate fetcher for the affected call.

Example fix

# narrow memory pressure: fetch in chunks
# before
df = fetcher.fetch_stock_data('600519', '2010-01-01', '2025-01-01')
# after
dfs = [fetcher.fetch_stock_data('600519', y, f'{int(y)+1}-01-01') for y in range(2010, 2025)]
Defensive patterns

Strategy: fallback

Validate before calling

# guard memory before batch runs
import shutil, os
free_mb = shutil.disk_usage('/').free // (1024 * 1024)
# and check container limits; a worker OOM is the top cause of EOFError on the pipe
assert free_mb > 512, 'low disk/memory conditions correlate with worker crashes'

Type guard

def is_akshare_worker_died(exc: Exception) -> bool:
    return isinstance(exc, RuntimeError) and '调用进程未返回结果' in str(exc)

Try / catch

try:
    df = fetcher.fetch_stock_data(code, start, end)
except RuntimeError as e:
    if '调用进程未返回结果' in str(e):
        df = fallback_fetcher.fetch_stock_data(code, start, end)  # worker crashed; switch source
    else:
        raise

Prevention

When it happens

Trigger: The multiprocessing worker calling an akshare function is killed by the OOM killer (large DataFrames in a memory-constrained container), segfaults in a C extension, or crashes on an unhandled native error; poll() succeeds but recv() raises EOFError.

Common situations: Docker/Kubernetes containers with low memory limits fetching long date ranges; macOS/Windows spawn start methods where unpicklable arguments kill the child; akshare/native dependency (pandas/numpy) ABI mismatch causing hard crashes.

Related errors


AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15). Data as JSON: /api/errors/29d00ad115a0df58. Report an issue: GitHub.