amir20/dozzle · error

unknown action

Error message

unknown action: %s

What it means

ContainerAction returns "unknown action: %s" when the given container.ContainerAction value is not one of Start, Stop, Restart, or Remove, so it cannot be mapped to a pb.ContainerAction enum for the gRPC call. It is a programming/client-side error, not a Docker error.

Solutions

  1. Add the missing case to the switch in ContainerAction (internal/agent/client.go) for the new container.ContainerAction value
  2. Validate user-supplied action input at the HTTP layer against the whitelist (start/stop/restart/remove) before calling the client
  3. Use only the exported container.Start/Stop/Restart/Remove constants, never raw numeric conversions
  4. Extend tests to cover every container.ContainerAction value mapping to a pb enum

Example fix

// before
action := container.ContainerAction(strings.TrimSpace(r.URL.Query().Get("action")))
err := client.ContainerAction(ctx, id, action)
// after
var action container.ContainerAction
switch r.URL.Query().Get("action") {
case "start": action = container.Start
case "stop": action = container.Stop
case "restart": action = container.Restart
case "remove": action = container.Remove
default:
    http.Error(w, "unsupported action", http.StatusBadRequest)
    return
}
err := client.ContainerAction(ctx, id, action)
Defensive patterns

Strategy: validation

Validate before calling

switch action {
case container.Start, container.Stop, container.Restart, container.Remove:
    // ok
default:
    return fmt.Errorf("unsupported action: %s", action)
}

Type guard

func supportedAction(a container.ContainerAction) bool {
    switch a { case container.Start, container.Stop, container.Restart, container.Remove: return true }
    return false
}

Try / catch

if err := client.ContainerAction(ctx, id, action); err != nil {
    if strings.HasPrefix(err.Error(), "unknown action") { http.Error(w, "unsupported action", 400); return }
    return err
}

Prevention

When it happens

Trigger: Calling client.ContainerAction(ctx, id, action) with an out-of-range container.ContainerAction value, e.g. a zero-value enum, an action added to container.ContainerAction but not yet mapped in the agent client, or an invalid value cast from an HTTP parameter.

Common situations: New container action added to internal/container without updating the switch in the agent client; web handler passing an unvalidated action string converted to the enum; tests constructing the enum with an invalid int.

Related errors


AI-assisted analysis of amir20/dozzle@d9463cbe21 (2026-09-07). Data as JSON: /api/errors/ea3c234988189a95. Report an issue: GitHub.

Appendix: source

Thrown at internal/agent/client.go:419

}

func (c *Client) ContainerAction(ctx context.Context, containerId string, action container.ContainerAction) error {
	var containerAction pb.ContainerAction
	switch action {
	case container.Start:
		containerAction = pb.ContainerAction_Start

	case container.Stop:
		containerAction = pb.ContainerAction_Stop

	case container.Restart:
		containerAction = pb.ContainerAction_Restart

	case container.Remove:
		containerAction = pb.ContainerAction_Remove

	default:
		return fmt.Errorf("unknown action: %s", action)
	}

	_, err := c.client.ContainerAction(ctx, &pb.ContainerActionRequest{ContainerId: containerId, Action: containerAction})

	return err
}

func (c *Client) UpdateContainer(ctx context.Context, containerID string, progressCh chan<- container.UpdateProgress) (bool, error) {
	defer close(progressCh)

	stream, err := c.client.UpdateContainer(ctx, &pb.UpdateContainerRequest{ContainerId: containerID})
	if err != nil {
		return false, err
	}

	updated := false
	for {
		progress, err := stream.Recv()

View on GitHub (pinned to d9463cbe21)