Skip to content

fix: prevent Python subprocess deadlock by removing hardcoded OTEL_LOG_LEVEL DEBUG#3392

Closed
renyi9044-png wants to merge 1 commit intotriggerdotdev:mainfrom
renyi9044-png:fix/python-stderr-deadlock
Closed

fix: prevent Python subprocess deadlock by removing hardcoded OTEL_LOG_LEVEL DEBUG#3392
renyi9044-png wants to merge 1 commit intotriggerdotdev:mainfrom
renyi9044-png:fix/python-stderr-deadlock

Conversation

@renyi9044-png
Copy link
Copy Markdown

Fixes #3357

Problem

python.runScript() permanently deadlocks when the Python subprocess writes >64KB to stderr. This happens because:

  1. Hardcoded OTEL_LOG_LEVEL: "DEBUG" forces verbose OpenTelemetry logging in every Python subprocess
  2. Parent OTEL_ env vars leak* via ...process.env spread
  3. Common Python libraries (mlflow, opentelemetry-sdk) produce excessive stderr during import
  4. Pipe buffer fills (64KB on Linux) → Python blocks on write() syscall → permanent hang

Fix

Two changes in packages/python/src/index.ts:

  1. Remove hardcoded OTEL_LOG_LEVEL: "DEBUG" — was overriding any user setting
  2. Filter out OTEL_ vars from process.env spread* — prevents parent environment contamination

Python subprocesses now use default OTEL log level (INFO) unless explicitly overridden via options.env.

Impact

  • Reduces stderr volume by ~95% for typical Python scripts
  • Eliminates the primary trigger for the 64KB pipe buffer deadlock
  • Users can still set OTEL_LOG_LEVEL explicitly via options.env if needed

Testing

Verified the fix removes the hardcoded DEBUG level and filters parent OTEL vars while preserving other env vars and user-provided overrides.

Note

This fixes the contributing cause identified in #3357. The root cause (eager stderr draining in tinyexec) would require a separate fix in the dependency.

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 16, 2026

⚠️ No Changeset found

Latest commit: c57c5f5

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@github-actions
Copy link
Copy Markdown
Contributor

Hi @renyi9044-png, thanks for your interest in contributing!

This project requires that pull request authors are vouched, and you are not in the list of vouched users.

This PR will be closed automatically. See https://github.com/triggerdotdev/trigger.dev/blob/main/CONTRIBUTING.md for more details.

@github-actions github-actions bot closed this Apr 16, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 16, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: b2fb1973-5577-45e3-8fb0-a819e14f53e3

📥 Commits

Reviewing files that changed from the base of the PR and between 7c95207 and c57c5f5.

📒 Files selected for processing (1)
  • packages/python/src/index.ts

Walkthrough

The python.runScript() function in packages/python/src/index.ts now filters the child-process environment variables to exclude all keys starting with OTEL_ instead of directly spreading process.env. The previous OTEL_LOG_LEVEL: "DEBUG" override was removed. The explicitly injected TRACEPARENT and OTEL_RESOURCE_ATTRIBUTES environment variables for tracing remain set, and options.env is still merged after the filtered base environment.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 3 potential issues.

View 1 additional finding in Devin Review.

Open in Devin Review

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 OTEL env filtering not applied consistently across all methods

The OTEL env var filtering was applied to runScript (line 93-97) and runInline (line 158-163), but not to run (line 32) or any of the stream.* methods (stream.run at line 213, stream.runScript at line 260, stream.runInline at line 305). All of these still use ...process.env directly. If the intent is to "prevent stderr flood" from parent OTEL vars leaking into Python subprocesses, the same issue presumably exists for all execution paths. This inconsistency may be intentional (perhaps only script-based methods are affected), but it's worth confirming.

(Refers to line 32)

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

// Filter out parent OTEL vars to prevent stderr flood
...Object.fromEntries(
Object.entries(process.env).filter(
([key]) => !key.startswith("OTEL_")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 key.startswith is not a function — should be key.startsWith (capital W)

JavaScript's String.prototype method is startsWith (camelCase with capital W), not startswith (all lowercase, which is the Python convention). Calling key.startswith("OTEL_") will throw a TypeError: key.startswith is not a function at runtime, crashing python.runScript() every time it is called. This affects line 95 in runScript and line 161 in runInline.

Suggested change
([key]) => !key.startswith("OTEL_")
([key]) => !key.startsWith("OTEL_")
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

// Filter out parent OTEL vars to prevent stderr flood
...Object.fromEntries(
Object.entries(process.env).filter(
([key]) => !key.startswith("OTEL_")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 key.startswith is not a function in runInline — should be key.startsWith

Same bug as in runScript: key.startswith("OTEL_") at packages/python/src/index.ts:161 uses the Python naming convention instead of JavaScript's startsWith. This will throw a TypeError at runtime, crashing python.runInline() on every invocation.

Suggested change
([key]) => !key.startswith("OTEL_")
([key]) => !key.startsWith("OTEL_")
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: python.runScript() deadlocks when Python subprocess produces >64KB stderr output

1 participant