amir20/dozzle · error

invalid host id

Error message

invalid host id: %s

What it means

downloadLogs expects each entry of the `id` path/query value to be a composite "host~containerId" token; it splits on "~" and requires exactly 2 parts. A 400 "invalid host id: %s" is returned when the separator is missing or there is more than one "~".

Solutions

  1. Build the identifier as `${hostId}~${containerId}` before calling the endpoint.
  2. Trim and re-check stored IDs/URLs for stale or malformed host~id values.
  3. Use the container object from the API (which already carries host and id fields) instead of hand-assembling strings.

Example fix

// before
fetch(`/api/hosts/${container.id}/download`)
// after
fetch(`/api/hosts/${container.host}~${container.id}/download`)
Defensive patterns

Strategy: validation

Validate before calling

function isCompositeId(id) {
  const parts = String(id).split('~');
  return parts.length === 2 && parts[0].length > 0 && parts[1].length > 0;
}
if (!isCompositeId(id)) throw new Error(`invalid host id: ${id}`)

Prevention

When it happens

Trigger: GET download endpoint with ids like "abc123" (no host prefix), "host~a~b", or an empty id, producing len(strings.Split(id, "~")) != 2.

Common situations: Old bookmarks/links predating the host~id scheme; callers passing a bare Docker container ID; frontend state that lost the host component; IDs echoed through other tools that split or re-join on different separators.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


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

Appendix: source

Thrown at internal/web/download.go:95

		for _, level := range r.URL.Query()["levels"] {
			levels[level] = struct{}{}
		}
	}

	// Validate all containers before starting to write response
	type containerInfo struct {
		hostId           string
		host             string
		id               string
		containerService *container_support.ContainerService
	}
	containers := make([]containerInfo, 0, len(hostIds))

	for _, hostId := range hostIds {
		parts := strings.Split(hostId, "~")
		if len(parts) != 2 {
			log.Error().Msgf("invalid host id: %s", hostId)
			http.Error(w, fmt.Sprintf("invalid host id: %s", hostId), http.StatusBadRequest)
			return
		}

		host := parts[0]
		id := parts[1]
		containerService, err := h.hostService.FindContainer(host, id, userLabels)
		if err != nil {
			log.Error().Err(err).Msgf("error finding container %s", id)
			http.Error(w, fmt.Sprintf("error finding container %s: %v", id, err), http.StatusBadRequest)
			return
		}

		containers = append(containers, containerInfo{
			hostId:           hostId,
			host:             host,
			id:               id,
			containerService: containerService,
		})

View on GitHub (pinned to d9463cbe21)