Skip to content

fix: move registerDefaultTools to constructor to prevent concurrent map writes#2041

Merged
dgageot merged 1 commit intodocker:mainfrom
dgageot:board/i-saw-this-error-fatal-error-concurrent-a877ee6e
Mar 10, 2026
Merged

fix: move registerDefaultTools to constructor to prevent concurrent map writes#2041
dgageot merged 1 commit intodocker:mainfrom
dgageot:board/i-saw-this-error-fatal-error-concurrent-a877ee6e

Conversation

@dgageot
Copy link
Member

@dgageot dgageot commented Mar 10, 2026

Problem

registerDefaultTools() was called inside the RunStream() goroutine, which writes to the plain map[string]ToolHandlerFunc field r.toolMap. When multiple goroutines call RunStream on the same LocalRuntime concurrently (e.g. background agent sessions), this causes a fatal error: concurrent map writes panic.

Fix

Move the r.registerDefaultTools() call from RunStream() to NewLocalRuntime(), so the map is fully populated during single-threaded construction. All subsequent accesses in processToolCalls are read-only, which is safe for concurrent goroutines.

Why this is safe

  • The handlers are method values on *LocalRuntime and never change.
  • r.bgAgents is already initialized before registerDefaultTools() is called.
  • No other code writes to r.toolMap after construction.

@dgageot dgageot requested a review from a team as a code owner March 10, 2026 15:46
Copy link

@docker-agent docker-agent bot left a comment

Choose a reason for hiding this comment

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

Review Summary

Assessment: 🟢 APPROVE

This is a correct concurrency fix. Moving registerDefaultTools() from the RunStream() goroutine to the NewLocalRuntime() constructor ensures that the toolMap is fully populated during single-threaded construction, preventing the fatal error: concurrent map writes panic when multiple goroutines call RunStream() concurrently.

What was verified:

  • The r.bgAgents field is already initialized before registerDefaultTools() is called in the constructor
  • The change maintains the correct initialization order
  • All subsequent accesses to r.toolMap in processToolCalls() are read-only, which is safe for concurrent goroutines
  • No other code writes to r.toolMap after construction

Concurrency safety:
✅ Single-threaded write during construction
✅ Concurrent read-only access during runtime
✅ No data races introduced

No issues found in the changed code.


// Register runtime-managed tool handlers once during construction.
// This avoids concurrent map writes when multiple goroutines call
// RunStream on the same runtime (e.g. background agent sessions).
Copy link
Member

Choose a reason for hiding this comment

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

Background agent sessions are using the same runtime??

Copy link
Member Author

Choose a reason for hiding this comment

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

As far as I understand, yes. I'm still trying to improve the code

@dgageot dgageot force-pushed the board/i-saw-this-error-fatal-error-concurrent-a877ee6e branch from b565b8b to 0f2ab92 Compare March 10, 2026 16:19
…ap writes

registerDefaultTools() was called inside the RunStream() goroutine, which
writes to the plain map r.toolMap. When multiple goroutines call RunStream
on the same LocalRuntime concurrently (e.g. background agent sessions),
this causes a fatal 'concurrent map writes' panic.

Move the call to NewLocalRuntime() so the map is fully populated before
any concurrent access. All subsequent reads in processToolCalls are safe
without synchronization.

Assisted-By: docker-agent
@dgageot dgageot force-pushed the board/i-saw-this-error-fatal-error-concurrent-a877ee6e branch from 0f2ab92 to af3b056 Compare March 10, 2026 16:23
@dgageot dgageot merged commit 8bf7424 into docker:main Mar 10, 2026
5 checks passed
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.

3 participants