Skip to content

fix: return an error when docker host cannot be retrieved#3613

Open
ash2k wants to merge 1 commit intotestcontainers:mainfrom
ash2k:no-panic
Open

fix: return an error when docker host cannot be retrieved#3613
ash2k wants to merge 1 commit intotestcontainers:mainfrom
ash2k:no-panic

Conversation

@ash2k
Copy link
Copy Markdown
Contributor

@ash2k ash2k commented Mar 27, 2026

What does this PR do?

When I run some of my tests without Docker running, they panic. I'd like them to just return an error from testcontainers.Run() (and everything that is built on top).

Why is it important?

It's not useful to get a panic when just a normal error is enough. Panic should be reserved for programming errors/etc - "Docker is not running" is not that.

Related issues

@ash2k ash2k requested a review from a team as a code owner March 27, 2026 01:51
@netlify
Copy link
Copy Markdown

netlify bot commented Mar 27, 2026

Deploy Preview for testcontainers-go ready!

Name Link
🔨 Latest commit 352b03e
🔍 Latest deploy log https://app.netlify.com/projects/testcontainers-go/deploys/69c5e28a2198c600080d0291
😎 Deploy Preview https://deploy-preview-3613--testcontainers-go.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 27, 2026

Summary by CodeRabbit

  • Bug Fixes
    • Improved error handling for Docker host resolution, preventing unexpected crashes and enabling graceful failure reporting.

Walkthrough

The changes replace panic-prone Docker host extraction calls (MustExtractDockerHost) with explicit error handling (ExtractDockerHost) across multiple files. A new non-panicking ExtractDockerHost function was introduced with error caching, while the Must variant now wraps it for backward compatibility.

Changes

Cohort / File(s) Summary
Docker Host Extraction Logic
internal/core/docker_host.go
Added ExtractDockerHost(ctx) function returning (string, error) with error caching. Modified MustExtractDockerHost(ctx) to wrap ExtractDockerHost and panic only on errors, maintaining backward compatibility.
Client Integration
internal/core/client.go, docker_client.go, provider.go
Updated three callsites to replace MustExtractDockerHost(ctx) with ExtractDockerHost(ctx), adding explicit error propagation and early returns on extraction failures instead of panics.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 No more panicking when hosts are astray,
Error returns show the proper way,
Cache it with care, both the truth and the fault,
Safe extraction now, worth its salt!
With Must as a wrapper, we're snug and quite neat,
This refactoring's rabbit-approved—what a treat! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: replacing panic behavior with error returns when Docker host cannot be retrieved.
Description check ✅ Passed The description is clearly related to the changeset, explaining the motivation for converting panics to errors when Docker is unavailable.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docker_client.go`:
- Around line 80-83: The cache flag dockerInfoSet is being set before host
resolution, so if core.ExtractDockerHost(ctx) fails the function returns an
error while leaving dockerInfoSet true and causing future Info() calls to return
a cached success; update Info() so dockerInfoSet is only set after
ExtractDockerHost succeeds (and any subsequent logging/processing completes) —
e.g., move the assignment that flips dockerInfoSet (or the code that writes
dockerInfo) to after the successful call to core.ExtractDockerHost(ctx) and any
error checks, or explicitly clear/unset dockerInfoSet on error paths of
ExtractDockerHost to ensure the cache is only marked initialized on success.

In `@internal/core/docker_host.go`:
- Around line 96-101: The code uses dockerHostOnce to cache both success and
failure in ExtractDockerHost, causing dockerHostErrCache to be sticky; change
the logic so dockerHostOnce (and dockerHostCache) only records on successful
extraction: call extractDockerHost inside a retryable path and only assign to
dockerHostCache and mark initialization (or call dockerHostOnce.Do) when
extractDockerHost returns nil error; if extractDockerHost returns an error,
return it directly without setting dockerHostErrCache so future calls can retry.
Update the related variables dockerHostOnce, dockerHostCache, dockerHostErrCache
and the call site of extractDockerHost to follow this pattern.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 64d4242b-1b52-498c-9c55-6f8f05a93aa9

📥 Commits

Reviewing files that changed from the base of the PR and between b7f3ae3 and 352b03e.

📒 Files selected for processing (4)
  • docker_client.go
  • internal/core/client.go
  • internal/core/docker_host.go
  • provider.go

Comment on lines +80 to +83
host, err := core.ExtractDockerHost(ctx)
if err != nil {
return dockerInfo, err
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Avoid marking docker info cache as initialized on host-resolution failure.

Line 82 introduces a normal error return path, but dockerInfoSet is already set earlier (Line 56). If host extraction fails once, subsequent Info() calls can incorrectly return cached success.

Suggested fix (set cache only after successful host extraction/logging path)
 	info, err := c.Client.Info(ctx)
 	if err != nil {
 		return info, fmt.Errorf("failed to retrieve docker info: %w", err)
 	}
-	dockerInfo = info
-	dockerInfoSet = true
@@
 	host, err := core.ExtractDockerHost(ctx)
 	if err != nil {
-		return dockerInfo, err
+		return info, err
 	}
 	log.Printf(infoMessage, packagePath,
@@
 		core.ProcessID(),
 	)
+	dockerInfo = info
+	dockerInfoSet = true
 
 	return dockerInfo, nil
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docker_client.go` around lines 80 - 83, The cache flag dockerInfoSet is being
set before host resolution, so if core.ExtractDockerHost(ctx) fails the function
returns an error while leaving dockerInfoSet true and causing future Info()
calls to return a cached success; update Info() so dockerInfoSet is only set
after ExtractDockerHost succeeds (and any subsequent logging/processing
completes) — e.g., move the assignment that flips dockerInfoSet (or the code
that writes dockerInfo) to after the successful call to
core.ExtractDockerHost(ctx) and any error checks, or explicitly clear/unset
dockerInfoSet on error paths of ExtractDockerHost to ensure the cache is only
marked initialized on success.

Comment on lines +96 to 101
func ExtractDockerHost(ctx context.Context) (string, error) {
dockerHostOnce.Do(func() {
dockerHostCache, dockerHostErrCache = extractDockerHost(ctx)
})

return dockerHostCache
return dockerHostCache, dockerHostErrCache
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Do not cache Docker host extraction errors process-wide.

At Line 97, sync.Once stores the first failure forever (dockerHostErrCache). A transient startup failure becomes unrecoverable for the lifetime of the process, even if Docker/environment is fixed later.

Suggested fix (cache success only, allow retry on errors)
 var (
-	dockerHostCache    string
-	dockerHostErrCache error
-	dockerHostOnce     sync.Once
+	dockerHostCache  string
+	dockerHostCached bool
+	dockerHostMu     sync.Mutex
 )
@@
 func ExtractDockerHost(ctx context.Context) (string, error) {
-	dockerHostOnce.Do(func() {
-		dockerHostCache, dockerHostErrCache = extractDockerHost(ctx)
-	})
-	return dockerHostCache, dockerHostErrCache
+	dockerHostMu.Lock()
+	defer dockerHostMu.Unlock()
+
+	if dockerHostCached {
+		return dockerHostCache, nil
+	}
+
+	host, err := extractDockerHost(ctx)
+	if err != nil {
+		return "", err
+	}
+
+	dockerHostCache = host
+	dockerHostCached = true
+	return dockerHostCache, nil
 }

Also applies to: 34-36

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/core/docker_host.go` around lines 96 - 101, The code uses
dockerHostOnce to cache both success and failure in ExtractDockerHost, causing
dockerHostErrCache to be sticky; change the logic so dockerHostOnce (and
dockerHostCache) only records on successful extraction: call extractDockerHost
inside a retryable path and only assign to dockerHostCache and mark
initialization (or call dockerHostOnce.Do) when extractDockerHost returns nil
error; if extractDockerHost returns an error, return it directly without setting
dockerHostErrCache so future calls can retry. Update the related variables
dockerHostOnce, dockerHostCache, dockerHostErrCache and the call site of
extractDockerHost to follow this pattern.

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.

1 participant