langchain - ✅(Solved) Fix CodSpeed Consistently Failing for libs/core with error 139 in CI Pipeline [1 pull requests, 3 comments, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
langchain-ai/langchain#35213Fetched 2026-04-08 00:27:13
View on GitHub
Comments
3
Participants
1
Timeline
9
Reactions
0
Participants
Timeline (top)
commented ×2labeled ×2closed ×1cross-referenced ×1

I am consistently getting 139 for libs/core for CodSpeed Benchmark in the CI Pipeline runs <img width="804" height="215" alt="Image" src="https://github.com/user-attachments/assets/01fcd2da-4b39-439a-bc0d-fd2419ac9543" /> Not sure why this is happening, have tried running it multiple times but keep getting 139 from CodSpeed, therefore causing the CI run to fail.

I have never used CodSpeed and am not familiar with it, therefore not sure why this is happening. It has started to happen since yesterday.

Error Message

============================= slowest 5 durations ============================== 5.13s call tests/benchmarks/test_imports.py::test_import_time[RunnableLambda] 4.89s call tests/benchmarks/test_imports.py::test_import_time[CallbackManager] 4.70s call tests/benchmarks/test_imports.py::test_import_time[HumanMessage] 4.62s call tests/benchmarks/test_imports.py::test_import_time[InMemoryVectorStore] 4.55s call tests/benchmarks/test_imports.py::test_import_time[ChatPromptTemplate] ============================= 13 passed in 58.74s ============================== Error: Error: failed to execute the benchmark process: exit status: 139 Error: Process completed with exit code 1.

Root Cause

I am consistently getting 139 for libs/core for CodSpeed Benchmark in the CI Pipeline runs <img width="804" height="215" alt="Image" src="https://github.com/user-attachments/assets/01fcd2da-4b39-439a-bc0d-fd2419ac9543" /> Not sure why this is happening, have tried running it multiple times but keep getting 139 from CodSpeed, therefore causing the CI run to fail.

I have never used CodSpeed and am not familiar with it, therefore not sure why this is happening. It has started to happen since yesterday.

Fix Action

Fix / Workaround

  • This is a bug, not a usage question.
  • I added a clear and descriptive title that summarizes this issue.
  • I used the GitHub search to find a similar question and didn't find it.
  • I am sure that this is a bug in LangChain rather than my code.
  • The bug is not resolved by updating to the latest stable version of LangChain (or the specific integration package).
  • This is not related to the langchain-community package.
  • I posted a self-contained, minimal, reproducible example. A maintainer can copy it and run it AS IS.

PR fix notes

PR #35239: fix(core): avoid inspect.getsource in RunnableLambda.deps

Description (problem / solution / changelog)

Summary

This PR fixes blocking behavior when computing RunnableLambda.deps by avoiding inspect.getsource in nonlocal discovery. Dependencies are now determined from bytecode analysis, which removes file I/O from the deps path and improves performance in async contexts.

Fixes #29530

Verification

  • uv run python -m pytest tests/unit_tests/runnables -q and ruff
  • Added a regression test ensuring RunnableLambda.deps does not call inspect.getsource.

Breaking changes

None.

Benchmarks

I ran some benchmarks locally on both a baseline checkout and this branch.

Results

Baseline

casegetsource?cold (ms)fresh (µs)recompute (µs)
direct_invokeyes0.286112.590.65
nested_attr_invokeyes0.245125.250.66
global_invokeyes0.268103.790.64
nested_two_levelsyes0.280138.170.66

This PR

casegetsource?cold (ms)fresh (µs)recompute (µs)
direct_invokeno0.0238.370.71
nested_attr_invokeno0.02213.280.69
global_invokeno0.0177.660.69
nested_two_levelsno0.02217.490.64

TLDR;

  • getsource? goes from yes → no in all cases.
  • Cold/fresh deps compute improves significantly in this microbenchmark and recompute is roughly unchanged.
<details> <summary>Benchmark code</summary>

import argparse
import gc
import statistics
import time
from dataclasses import dataclass
from typing import Callable, Dict, List, Tuple

from langchain_core.runnables import RunnableLambda
import langchain_core.runnables.utils as utils


# ----------------------------
# Test case builders
# ----------------------------

def case_direct_invoke() -> RunnableLambda:
    """agent.invoke(x) where agent is a captured RunnableLambda."""
    agent = RunnableLambda(lambda x: x)

    def my_func(x: str) -> str:
        return agent.invoke(x)

    return RunnableLambda(my_func)


def case_nested_attr_invoke() -> RunnableLambda:
    """box.agent.invoke(x) where box is captured and agent is an attribute."""
    agent = RunnableLambda(lambda x: x)

    class Box:
        def __init__(self, a):
            self.agent = a

    box = Box(agent)

    def my_func(x: str) -> str:
        return box.agent.invoke(x)

    return RunnableLambda(my_func)


def case_global_invoke() -> RunnableLambda:
    """GLOBAL_AGENT.invoke(x) where GLOBAL_AGENT is a module global."""
    global GLOBAL_AGENT
    GLOBAL_AGENT = RunnableLambda(lambda x: x)  # noqa: PLW0603

    def my_func(x: str) -> str:
        return GLOBAL_AGENT.invoke(x)

    return RunnableLambda(my_func)


def case_nested_two_levels() -> RunnableLambda:
    """outer.inner.agent.invoke(x) (deeper attribute chain)."""
    agent = RunnableLambda(lambda x: x)

    class Inner:
        def __init__(self, a):
            self.agent = a

    class Outer:
        def __init__(self, inner):
            self.inner = inner

    outer = Outer(Inner(agent))

    def my_func(x: str) -> str:
        return outer.inner.agent.invoke(x)

    return RunnableLambda(my_func)


CASES: Dict[str, Callable[[], RunnableLambda]] = {
    "direct_invoke": case_direct_invoke,
    "nested_attr_invoke": case_nested_attr_invoke,
    "global_invoke": case_global_invoke,
    "nested_two_levels": case_nested_two_levels,
}


# ----------------------------
# Helpers
# ----------------------------

def ns_now() -> int:
    return time.perf_counter_ns()


def time_one_call_ns(fn: Callable[[], None]) -> int:
    t0 = ns_now()
    fn()
    t1 = ns_now()
    return t1 - t0


def find_deps_cache_keys(r: RunnableLambda) -> List[str]:
    """Find which __dict__ keys appear after first computing deps."""
    before = set(r.__dict__.keys())
    _ = r.deps
    after = set(r.__dict__.keys())
    return sorted(after - before)


def clear_cache_keys(r: RunnableLambda, keys: List[str]) -> None:
    for k in keys:
        r.__dict__.pop(k, None)


def detect_getsource_called_when_computing_deps(maker: Callable[[], RunnableLambda]) -> Tuple[bool, str]:
    """
    Returns (called, error_message).
    - called=True if utils.inspect.getsource was invoked during r.deps
    - error_message is non-empty if r.deps raised some other error
    """
    r = maker()
    original_getsource = utils.inspect.getsource
    called = False

    def wrapped_getsource(*args, **kwargs):
        nonlocal called
        called = True
        return original_getsource(*args, **kwargs)

    utils.inspect.getsource = wrapped_getsource
    try:
        _ = r.deps
        return called, ""
    except Exception as e:
        # still restore, then report error
        return called, f"{type(e).__name__}: {e}"
    finally:
        utils.inspect.getsource = original_getsource


@dataclass
class Result:
    case: str
    getsource_called: str  # "yes"/"no"/"error"
    cold_ms: float
    fresh_us: float
    recompute_us: float


def bench_case(
    name: str,
    maker: Callable[[], RunnableLambda],
    n_fresh: int,
    n_recompute: int,
    repeats: int,
    do_gc: bool,
) -> Result:
    """
    Benchmarks:
      - cold_ms: first deps on a fresh runnable
      - fresh_us: avg deps cost when building a fresh runnable each iteration
      - recompute_us: avg deps cost when forcing recompute on same runnable by clearing cache keys
    Reports medians over repeats.
    """
    called, err = detect_getsource_called_when_computing_deps(maker)
    if err:
        getsource_flag = "error"
    else:
        getsource_flag = "yes" if called else "no"

    # Determine cache keys used by deps on this version (using this case)
    probe = maker()
    cache_keys = find_deps_cache_keys(probe)

    cold_samples_ms: List[float] = []
    fresh_samples_us: List[float] = []
    recompute_samples_us: List[float] = []

    for _ in range(repeats):
        if do_gc:
            gc.collect()

        # Cold
        r = maker()
        cold_ns = time_one_call_ns(lambda: getattr(r, "deps"))
        cold_samples_ms.append(cold_ns / 1e6)

        # Fresh instances
        def fresh_loop():
            for __ in range(n_fresh):
                rr = maker()
                _ = rr.deps

        fresh_ns = time_one_call_ns(fresh_loop)
        fresh_samples_us.append((fresh_ns / n_fresh) / 1e3)

        # Forced recompute on same instance
        r = maker()
        _ = r.deps  # establish cache
        def recompute_loop():
            for __ in range(n_recompute):
                clear_cache_keys(r, cache_keys)
                _ = r.deps

        recompute_ns = time_one_call_ns(recompute_loop)
        recompute_samples_us.append((recompute_ns / n_recompute) / 1e3)

    return Result(
        case=name,
        getsource_called=getsource_flag,
        cold_ms=statistics.median(cold_samples_ms),
        fresh_us=statistics.median(fresh_samples_us),
        recompute_us=statistics.median(recompute_samples_us),
    )


# ----------------------------
# Main
# ----------------------------

def main() -> None:
    p = argparse.ArgumentParser(description="RunnableLambda.deps: detect inspect.getsource usage + benchmark")
    p.add_argument("--cases", default="all", help="Comma-separated case names or 'all'")
    p.add_argument("--n-fresh", type=int, default=5000, help="Iterations for fresh-instance benchmark")
    p.add_argument("--n-recompute", type=int, default=2000, help="Iterations for forced recompute benchmark")
    p.add_argument("--repeats", type=int, default=7, help="Repeat count; median reported")
    p.add_argument("--no-gc", action="store_true", help="Disable gc.collect() between repeats")
    args = p.parse_args()

    if args.cases.strip().lower() == "all":
        selected = list(CASES.keys())
    else:
        selected = [c.strip() for c in args.cases.split(",") if c.strip()]
        unknown = [c for c in selected if c not in CASES]
        if unknown:
            raise SystemExit(f"Unknown case(s): {unknown}. Options: {list(CASES.keys())}")

    # Show cache keys for a representative case
    probe = case_nested_attr_invoke()
    print("deps cache keys added after first compute:", find_deps_cache_keys(probe))
    print()

    results: List[Result] = []
    for name in selected:
        results.append(
            bench_case(
                name=name,
                maker=CASES[name],
                n_fresh=args.n_fresh,
                n_recompute=args.n_recompute,
                repeats=args.repeats,
                do_gc=not args.no_gc,
            )
        )

    header = f"{'case':20} {'getsource?':>10} {'cold(ms)':>10} {'fresh(us)':>12} {'recompute(us)':>14}"
    print(header)
    print("-" * len(header))
    for r in results:
        print(f"{r.case:20} {r.getsource_called:>10} {r.cold_ms:10.3f} {r.fresh_us:12.2f} {r.recompute_us:14.2f}")


if __name__ == "__main__":
    main()
</details>

cc : @cbornet , @eyurtsev

Changed files

  • libs/core/langchain_core/runnables/utils.py (modified, +135/-29)
  • libs/core/tests/unit_tests/runnables/test_utils.py (modified, +34/-1)

Code Example

N/A

---

============================= slowest 5 durations ==============================
  5.13s call     tests/benchmarks/test_imports.py::test_import_time[RunnableLambda]
  4.89s call     tests/benchmarks/test_imports.py::test_import_time[CallbackManager]
  4.70s call     tests/benchmarks/test_imports.py::test_import_time[HumanMessage]
  4.62s call     tests/benchmarks/test_imports.py::test_import_time[InMemoryVectorStore]
  4.55s call     tests/benchmarks/test_imports.py::test_import_time[ChatPromptTemplate]
  ============================= 13 passed in 58.74s ==============================
  Error: Error: failed to execute the benchmark process: exit status: 139
  Error: Process completed with exit code 1.
RAW_BUFFERClick to expand / collapse

Checked other resources

  • This is a bug, not a usage question.
  • I added a clear and descriptive title that summarizes this issue.
  • I used the GitHub search to find a similar question and didn't find it.
  • I am sure that this is a bug in LangChain rather than my code.
  • The bug is not resolved by updating to the latest stable version of LangChain (or the specific integration package).
  • This is not related to the langchain-community package.
  • I posted a self-contained, minimal, reproducible example. A maintainer can copy it and run it AS IS.

Package (Required)

  • langchain
  • langchain-openai
  • langchain-anthropic
  • langchain-classic
  • langchain-core
  • langchain-model-profiles
  • langchain-tests
  • langchain-text-splitters
  • langchain-chroma
  • langchain-deepseek
  • langchain-exa
  • langchain-fireworks
  • langchain-groq
  • langchain-huggingface
  • langchain-mistralai
  • langchain-nomic
  • langchain-ollama
  • langchain-perplexity
  • langchain-qdrant
  • langchain-xai
  • Other / not sure / general

Related Issues / PRs

No response

Reproduction Steps / Example Code (Python)

N/A

Error Message and Stack Trace (if applicable)

============================= slowest 5 durations ==============================
  5.13s call     tests/benchmarks/test_imports.py::test_import_time[RunnableLambda]
  4.89s call     tests/benchmarks/test_imports.py::test_import_time[CallbackManager]
  4.70s call     tests/benchmarks/test_imports.py::test_import_time[HumanMessage]
  4.62s call     tests/benchmarks/test_imports.py::test_import_time[InMemoryVectorStore]
  4.55s call     tests/benchmarks/test_imports.py::test_import_time[ChatPromptTemplate]
  ============================= 13 passed in 58.74s ==============================
  Error: Error: failed to execute the benchmark process: exit status: 139
  Error: Process completed with exit code 1.

Description

I am consistently getting 139 for libs/core for CodSpeed Benchmark in the CI Pipeline runs <img width="804" height="215" alt="Image" src="https://github.com/user-attachments/assets/01fcd2da-4b39-439a-bc0d-fd2419ac9543" /> Not sure why this is happening, have tried running it multiple times but keep getting 139 from CodSpeed, therefore causing the CI run to fail.

I have never used CodSpeed and am not familiar with it, therefore not sure why this is happening. It has started to happen since yesterday.

System Info

N/A

extent analysis

Problem Summary

The issue is a CI pipeline failure due to a 139 exit code from the CodSpeed Benchmark for libs/core.

Root Cause Analysis

The root cause is likely a memory issue or a resource leak in the libs/core module.

Fix Plan

To fix this issue, follow these steps:

1. Check Memory Usage

Check the memory usage of the libs/core module during the benchmark process. If it's consuming too much memory, it may be causing the 139 exit code.

2. Optimize Memory Usage

Optimize the memory usage of the libs/core module by:

  • Reducing the number of objects created during the benchmark process
  • Using more efficient data structures
  • Implementing a garbage collector to free up unused memory

3. Use a Memory Profiler

Use a memory profiler like memory_profiler to identify memory leaks and optimize the code accordingly.

4. Update Dependencies

Update the dependencies of the libs/core module to the latest versions to ensure that any memory-related issues are fixed.

5. Implement a Retry Mechanism

Implement a retry mechanism to handle the 139 exit code and prevent the CI pipeline from failing.

Example Code (Python)

import time
import psutil

def benchmark_process():
    # Code for the benchmark process
    pass

def check_memory_usage():
    process = psutil.Process()
    memory_usage = process.memory_info().rss / (1024 * 1024)
    if memory_usage > 512:  # 512 MB threshold
        raise MemoryError("Memory usage exceeded threshold")

def optimize_memory_usage():
    # Reduce memory usage by reducing object creation
    # Use more efficient data structures
    # Implement a garbage collector
    pass

def use_memory_profiler():
    import memory_profiler
    memory_profiler.memory_usage((benchmark_process, ()))

def

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING