amir20/dozzle · error

cloud: search

Error message

cloud: search: %w

What it means

SearchLogs issues a cloud-side log search RPC (with limit, host/container IDs, and a before-timestamp) and wraps any RPC error as 'cloud: search: %w'. The failure comes from the gRPC call itself, not the search results. The underlying status is preserved for programmatic handling.

Solutions

  1. Unwrap and inspect the gRPC status code (codes.PermissionDenied means API key/plan issue)
  2. Validate limit and timestamp inputs are within server-accepted ranges before the call
  3. Check connectivity to the cloud endpoint and retry with backoff for transient codes
  4. Confirm the host/container IDs exist and are accessible to the account
Defensive patterns

Strategy: retry

Validate before calling

if limit <= 0 || limit > maxSearchLimit {
    return fmt.Errorf("limit must be 1..%d", maxSearchLimit)
}
if before < 0 {
    return fmt.Errorf("before timestamp must be non-negative")
}

Try / catch

resp, err := client.SearchLogs(ctx, req)
if err != nil {
    if status.Code(err) == codes.PermissionDenied { return nil, err }
    if status.Code(err) == codes.Unavailable {
        time.Sleep(backoff); return retry(req)
    }
    return nil, err
}

Prevention

When it happens

Trigger: Calling SearchLogs when the cloud RPC fails: connection dropped, PermissionDenied from an invalid API key, invalid arguments rejected server-side, or a deadline/context cancellation.

Common situations: Cloud service outage, account without pro plan, oversized or out-of-range query parameters (limit/timestamps) rejected by the server, network egress blocked in restricted deployments.

Understand the failure class

Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.

Related errors


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

Appendix: source

Thrown at internal/cloud/search.go:102

	if err != nil {
		return nil, err
	}

	mdPairs := []string{"x-api-key", apiKey}
	if c.instanceID != "" {
		mdPairs = append(mdPairs, "x-instance-id", c.instanceID)
	}
	callCtx := metadata.NewOutgoingContext(ctx, metadata.Pairs(mdPairs...))

	resp, err := client.SearchLogs(callCtx, &pb.SearchLogsRequest{
		Query:       query,
		Limit:       limit,
		HostId:      hostID,
		ContainerId: containerID,
		BeforeTsNs:  before,
	})
	if err != nil {
		return nil, fmt.Errorf("cloud: search: %w", err)
	}

	hits := make([]SearchLogHit, 0, len(resp.GetHits()))
	for _, h := range resp.GetHits() {
		hits = append(hits, SearchLogHit{
			TimestampNs:   h.GetTimestampNs(),
			HostID:        h.GetHostId(),
			ContainerID:   h.GetContainerId(),
			ContainerName: h.GetContainerName(),
			Message:       h.GetMessage(),
			Stream:        h.GetStream(),
			Level:         h.GetLevel(),
			LogID:         h.GetLogId(),
		})
	}
	return &SearchLogResult{
		Hits:       hits,
		HasMore:    resp.GetHasMore(),

View on GitHub (pinned to d9463cbe21)