Skip to content

Conversation

@sauerdaniel
Copy link
Contributor

@sauerdaniel sauerdaniel commented Jan 17, 2026

Summary

Fix various small memory leaks from uncleaned timeouts, intervals, and event subscriptions across the codebase.

Fixes #9156

Problems

1. WebFetch Timeout (webfetch.ts)

When fetch throws an error, the timeout is not cleared.

2. Models setInterval (models.ts)

A setInterval is created but never cleared, even when the module is unloaded.

3. Bus.subscribe Return Value (github.ts)

The unsubscribe function returned by Bus.subscribe() is not captured or called.

Solution

WebFetch - Use try/finally

const timeout = setTimeout(...)
try {
  const response = await fetch(...)
  return response
} finally {
  clearTimeout(timeout)
}

Models - Track interval for cleanup

const intervalId = setInterval(...)
process.on("exit", () => clearInterval(intervalId))

Bus.subscribe - Capture unsubscribe

Store the unsubscribe function for later cleanup.

Changes

  • packages/opencode/src/util/webfetch.ts - Clear timeout in finally block
  • packages/opencode/src/provider/models.ts - Add interval cleanup on exit
  • packages/opencode/src/github/github.ts - Capture Bus.subscribe return value

Testing

  • TypeScript compilation passes (bun turbo typecheck)
  • Unit tests pass (725 tests, 0 failures)

Note: Manual testing of timeout/interval cleanup requires runtime verification which was not performed.

Prevent memory leak in webfetch tool when fetch fails before timeout
triggers. Ensures timeout handle is properly cleared on all exit paths.
Clear setInterval timer on shutdown to prevent memory leak from
orphaned interval callback references.
Store and call unsubscribe function returned by Bus.subscribe to
properly clean up event handlers when no longer needed.
@github-actions
Copy link
Contributor

Thanks for your contribution!

This PR doesn't have a linked issue. All PRs must reference an existing issue.

Please:

  1. Open an issue describing the bug/feature (if one doesn't exist)
  2. Add Fixes #<number> or Closes #<number> to this PR description

See CONTRIBUTING.md for details.

@github-actions
Copy link
Contributor

The following comment was made by an LLM, it may be inaccurate:

Potential Related PRs Found:

  1. fix(memory): Fix event listener leaks in TUI and Slack bot #9147 - "fix(memory): Fix event listener leaks in TUI and Slack bot"

    • Related memory cleanup fix, likely part of same cleanup initiative
  2. fix(acp): Fix memory leak in session event streams #9146 - "fix(acp): Fix memory leak in session event streams"

    • Related memory leak fix in event streams
  3. fix(mcp): Fix memory leaks in OAuth transport and process cleanup #9145 - "fix(mcp): Fix memory leaks in OAuth transport and process cleanup"

    • Related memory leak fixes across the codebase
  4. fix(core): add dispose functions to prevent subscription memory leaks #7914 - "fix(core): add dispose functions to prevent subscription memory leaks"

  5. fix(core): add dispose functions to prevent subscription memory leaks #7032 - "fix(core): add dispose functions to prevent subscription memory leaks"

    • Previous attempt at addressing subscription memory leaks
  6. Add timeout for file watcher subscribe to address hangs on Rosetta x86 emulation #5350 - "Add timeout for file watcher subscribe to address hangs on Rosetta x86 emulation"

    • Related to timeout handling

These appear to be part of a broader memory leak cleanup effort (related to issue #5363 mentioned in the PR). PRs #9145, #9146, and #9147 are particularly close in scope and timing, suggesting they may be related fixes across different modules. Consider checking if any of these address the same files or can be consolidated.

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.

Memory leak: Uncleaned timeouts, intervals, and subscriptions

1 participant