Skip to content

[node] SIGSEGV (exit 139) on linux-x64-musl under concurrent fetch/text() load; event loop stalls before the crash (0.14.5) #570

Open

Description

@muhamed-didovic

Summary

A long-running scraper using impit 0.14.5 (npm, impit-linux-x64-musl) dies with SIGSEGV (exit code 139) in roughly 6.5% of production runs. The crash is preceded by a long event-loop stall: our 45-second heartbeat timer stops firing 60–100+ seconds before the process dies, while the container stays alive. No JS exception is thrown and nothing reaches stderr, so the crash cannot be observed from inside the process.

This looks like a relative of #498 (fixed in js-0.14.3, exit 132/133 on concurrent body-read failures). Upgrading 0.14.1 → 0.14.5 cut our orphaned-run rate from ~14% to ~6.5%, but this second crash mode remains, now as a plain segfault.

Environment

  • impit 0.14.5 (npm), binary impit-linux-x64-musl
  • Node v24.18.0, apify/actor-node:24 Docker image (Alpine), 512–1024 MB containers
  • Linux x64 (Apify platform). The same workload on darwin-arm64 has not reproduced the crash.

Usage pattern

  • One long-lived new Impit({ browser: 'firefox', proxyUrl, timeout: 45_000, http3: false, ignoreTlsErrors: true }) per run; proxyUrl is a rotating residential proxy with per-session credentials.
  • Additional short-lived instances are created for retries (same options, fresh proxy session).
  • Up to 5 concurrent impit.fetch() + await response.text() on the shared instance at peak; the rest of the pipeline is sequential.
  • Residential exits fail often here: connection refused, TLS handshake failures, read timeouts. The crash correlates with runs on flakier exits, which is why concurrent body-read failures (the [node] Process crashes (SIGTRAP/SIGSEGV) when multiple response body reads fail concurrently (e.g. read timeouts) #498 trigger) remain our main suspect.

Observed behavior across one week of production runs

  • 232 runs, 15 ended in a hard kill with no graceful end: typical signature is normal progress, then timers stop firing, then SIGSEGV. One run died 115 s after start without ever reaching its first 45 s heartbeat.
  • Exit code is 139. Nothing on stderr, no abort message, no V8 check failure text (unlike the pre-0.14.3 crash, which printed Check failed: node->IsInUse()).
  • Crashes occur across different inputs; re-running a crashed input succeeds, so it is a race, not data-dependent.

What we don't have

No core dump (platform containers) and no minimal reproduction yet, since it needs a flaky proxy to trigger. Happy to run a debug build or set env flags on a subset of production runs if that helps capture a backtrace.

As a mitigation we are serializing response.text() calls so no two body reads can fail in the same instant; too early to say whether that eliminates it.

Activity

  1. added
    t-toolingIssues with this label are in the ownership of the tooling team.
    on Oct 14, 2026
  2. muhamed-didovic commented on Oct 14, 2026

    @muhamed-didovic
    Author

    Update after more digging: the dominant cause of our orphaned runs was on our side, not in impit. Reproducing a crashed run's input as an owner run gave us readable logs, and the process was dying of V8 heap exhaustion (FATAL ERROR: Reached heap limit): we fed multi-megabyte, script-heavy publisher pages to jsdom in a container with a ~255 MB heap. The long GC pauses on the way down also explain the event-loop stalls we described. Stripping scripts/styles before the DOM parse fixed it; the same input now completes on the same container size.

    Two things may still be of interest here. The timeout option does not appear to bound body streaming: a page that keeps streaming lets response.text() buffer indefinitely (we now read through response.body with a byte cap and cancel the reader). And our original exit code was 139 rather than the 134 a V8 heap abort usually produces, so a native component in the crash path is possible but unproven. Happy for this to be closed if nothing actionable remains on your side; if we see segfaults persist now that memory is bounded, I'll reopen with fresh evidence.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    t-toolingIssues with this label are in the ownership of the tooling team.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions