{"record":{"id":"80474f1e53eca803","repo":"amir20/dozzle","slug":"cloud-no-api-key-configured","errorCode":null,"errorMessage":"cloud: no API key configured","messagePattern":"cloud: no API key configured","errorType":"error_code","errorClass":"ErrNotConfigured","httpStatus":503,"severity":"info","filePath":"internal/cloud/search.go","lineNumber":46,"sourceCode":"// instance's (user_id, api_key_id) — Cloud derives those from the auth\n// metadata, never the request body.\ntype SearchLogHit struct {\n\tTimestampNs   int64  `json:\"ts\"`\n\tHostID        string `json:\"hostId\"`\n\tContainerID   string `json:\"containerId\"`\n\tContainerName string `json:\"containerName\"`\n\tMessage       string `json:\"message\"`\n\tStream        string `json:\"stream\"`\n\tLevel         string `json:\"level\"`\n\t// LogID is Dozzle's FNV-32a hash of the original line. Lets the UI\n\t// build deep-links matching \"Copy permalink\" output. Omitted when the\n\t// row predates indexing (older Dozzle clients sent 0).\n\tLogID uint32 `json:\"logId,omitempty\"`\n}\n\n// ErrNotConfigured is returned when SearchLogs is called but no Cloud API key\n// is available (the user hasn't linked Cloud yet). Callers map this to a 503.\nvar ErrNotConfigured = errors.New(\"cloud: no API key configured\")\n\n// unaryServiceClient returns a (lazily dialed) reusable gRPC client. The\n// underlying conn is shared across every Dozzle-initiated unary call so we pay\n// the TLS handshake once per process — not once per keystroke or scroll.\nfunc (c *Client) unaryServiceClient() (pb.CloudToolServiceClient, error) {\n\tc.unaryConnMu.Lock()\n\tdefer c.unaryConnMu.Unlock()\n\tif c.unaryClient != nil {\n\t\treturn c.unaryClient, nil\n\t}\n\tvar creds grpc.DialOption\n\tif c.plaintext {\n\t\tcreds = grpc.WithTransportCredentials(insecure.NewCredentials())\n\t} else {\n\t\tcreds = grpc.WithTransportCredentials(credentials.NewClientTLSFromCert(nil, \"\"))\n\t}\n\tconn, err := grpc.NewClient(c.target, creds)\n\tif err != nil {","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/amir20/dozzle/blob/d9463cbe21874e44ab79db6fa63e746ca7d22928/internal/cloud/search.go#L28-L64","documentation":"ErrNotConfigured in internal/cloud/search.go signals that Cloud search/alert calls (SearchLogs, GetAlerts) were made but apiKeyFunc returned an empty string, i.e. Dozzle Cloud was never linked. The HTTP layer maps it to a 503 so callers know the feature is unavailable rather than broken.","triggerScenarios":"cloudSearchLogs or cloudAlerts invoked with no API key: the user hasn't linked Cloud, the API-key env/config is unset, or the key was cleared from settings before a search request arrived.","commonSituations":"Frontend calls log search before the user completes Cloud linking; DOZZLE_API_KEY (or equivalent config) missing in the deployment; key removed after subscription lapse while UI still exposes search.","solutions":["Link Dozzle Cloud / set the API key so apiKeyFunc returns a non-empty value","Check the Cloud configuration (env var or settings) on the Dozzle instance","Handle ErrNotConfigured client-side by showing a 'link Cloud' prompt instead of a search request","Gate search/alert UI on a config feature flag when no API key is present"],"exampleFix":"apiKey := c.apiKeyFunc()\nif apiKey == \"\" {\n    return nil, ErrNotConfigured // caller maps to 503\n}","handlingStrategy":"fallback","validationCode":"// before issuing a cloud search from the frontend\nif (!config.features.cloudSearch) {\n  showCloudLinkPrompt();\n  return;\n}","typeGuard":null,"tryCatchPattern":"alerts, err := client.GetAlerts(ctx)\nif errors.Is(err, cloud.ErrNotConfigured) {\n    return nil, status.Error(codes.Unavailable, \"cloud not linked\") // or serve local results\n}","preventionTips":["Set the Cloud API key in config/env before enabling search/alert UI","Expose a feature flag so the UI can hide cloud search when unlinked","Check errors.Is(err, ErrNotConfigured) to distinguish 'not linked' from real failures"],"tags":["cloud","go","api-key","not-configured"],"backgroundTag":"missing-api-key","analyzedSha":"d9463cbe21874e44ab79db6fa63e746ca7d22928","analyzedAt":"2026-09-07T10:08:55.855Z","contentChangedAt":"2026-09-07T10:08:55.855Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}