amir20/dozzle · error
container_id is required
Error message
container_id is required
What it means
matchContainerTier trims the containerRef and rejects an empty string up front with 'container_id is required', before any host listing occurs. Both the strict and read resolvers route through this guard.
Solutions
- Always pass a non-empty container_id string
- Resolve the id first with find_containers if unknown
- Check argument assembly for variables that may expand to empty strings
Example fix
// before
const id = process.env.CONTAINER_ID || ""
fetchLogs({container_id: id})
// after
if (!process.env.CONTAINER_ID) throw new Error("CONTAINER_ID must be set")
fetchLogs({container_id: process.env.CONTAINER_ID}) Defensive patterns
Strategy: validation
Validate before calling
if (typeof containerId !== 'string' || containerId.trim() === '') throw new Error('container_id must be a non-empty string'); Type guard
function isNonEmptyString(v) { return typeof v === 'string' && v.trim().length > 0; }
// guard: isNonEmptyString(args.container_id) Prevention
- Validate arguments before every container tool call
- Guard against env vars / form inputs expanding to empty strings
- Resolve unknown ids via find_containers first
When it happens
Trigger: Any container tool (actions, update, inspect, logs) invoked with container_id omitted, null, or an empty/whitespace-only string.
Common situations: Tool-call argument assembly dropping an empty variable; LLM omitting the parameter; scripts interpolating an unset env var so the field arrives as ''.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- container_id is required
- unknown action
- invalid start time format (expected RFC3339)
- invalid end time format (expected RFC3339)
- invalid regex pattern
AI-assisted analysis of amir20/dozzle@d9463cbe21 (2026-09-07).
Data as JSON: /api/errors/71104fcf29e5542f.
Report an issue: GitHub.
Appendix: source
Thrown at internal/cloud/tools_resolve.go:142
// replicas (pick the newest live one).
if live := runningContainers(tier); len(live) == 1 {
return live[0].Host, live[0].ID, "", nil
}
best := bestCandidate(tier)
note = resolutionNote(strings.TrimSpace(containerRef), best, tier, hostNames)
return best.Host, best.ID, note, nil
}
}
// matchContainerTier runs the shared scoping + tiered matching used by both
// resolvers and returns the winning tier (the first non-empty of exact-id,
// exact-name, substring). It also returns the trimmed hostRef, the resolved
// scoped host id (empty when no host was supplied), and the host-name map for
// building human-readable notes/errors. An empty returned tier means no match.
func matchContainerTier(containerRef, hostRef string, deps ToolDeps) (tier []container.Container, trimmedHostRef, scopedHostID string, hostNames map[string]string, err error) {
containerRef = strings.TrimSpace(containerRef)
if containerRef == "" {
return nil, "", "", nil, fmt.Errorf("container_id is required")
}
containers, errs := deps.HostService.ListAllContainers(deps.Labels)
logHostErrors(errs)
hostNames = buildHostNameMap(deps.HostService)
// Scope to a host if one was supplied. The host reference may be an id or a
// name; an unknown host is an explicit error rather than a silent no-match.
trimmedHostRef = strings.TrimSpace(hostRef)
if trimmedHostRef != "" {
scopedHostID, err = resolveHostRef(trimmedHostRef, deps)
if err != nil {
return nil, trimmedHostRef, "", hostNames, err
}
filtered := containers[:0:0]
for _, c := range containers {
if c.Host == scopedHostID {
filtered = append(filtered, c)View on GitHub (pinned to d9463cbe21)