{"record":{"id":"dde59918c23a421a","repo":"crowdsecurity/crowdsec","slug":"loki-is-not-ready-w","errorCode":null,"errorMessage":"loki is not ready: %w","messagePattern":"loki is not ready: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/acquisition/modules/loki/run.go","lineNumber":30,"sourceCode":"\t\"github.com/prometheus/client_golang/prometheus\"\n\ttomb \"gopkg.in/tomb.v2\"\n\n\t\"github.com/crowdsecurity/crowdsec/pkg/acquisition/modules/loki/internal/lokiclient\"\n\t\"github.com/crowdsecurity/crowdsec/pkg/metrics\"\n\t\"github.com/crowdsecurity/crowdsec/pkg/pipeline\"\n)\n\n// OneShotAcquisition reads a set of file and returns when done\nfunc (l *Source) OneShotAcquisition(ctx context.Context, out chan pipeline.Event, t *tomb.Tomb) error {\n\tl.logger.Debug(\"Loki one shot acquisition\")\n\tl.Client.SetTomb(t)\n\n\tif !l.Config.NoReadyCheck {\n\t\treadyCtx, readyCancel := context.WithTimeout(ctx, l.Config.WaitForReady)\n\t\tdefer readyCancel()\n\n\t\tif err := l.Client.Ready(readyCtx); err != nil {\n\t\t\treturn fmt.Errorf(\"loki is not ready: %w\", err)\n\t\t}\n\t}\n\n\tlokiCtx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\n\tc := l.Client.QueryRange(lokiCtx, false)\n\n\tfor {\n\t\tselect {\n\t\tcase <-t.Dying():\n\t\t\tl.logger.Debug(\"Loki one shot acquisition stopped\")\n\t\t\treturn nil\n\t\tcase resp, ok := <-c:\n\t\t\tif !ok {\n\t\t\t\tl.logger.Info(\"Loki acquisition done, chan closed\")\n\t\t\t\treturn nil\n\t\t\t}","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/acquisition/modules/loki/run.go#L12-L48","documentation":"Before one-shot acquisition, the Loki source probes the server's /ready endpoint within the WaitForReady window (skipped only when NoReadyCheck is set). Any failure from Client.Ready — connection refused, 503 not-ready, timeout — is wrapped as 'loki is not ready'.","triggerScenarios":"Calling OneShotAcquisition after Configure/ConfigureByDSN when the Loki URL points at a host that is down, still booting, or answering /ready with a non-200 within wait_for_ready.","commonSituations":"crowdsec started by orchestration before Loki finishes booting; wrong Loki host/port in the DSN; wait_for_ready shorter than Loki's cold-start time.","solutions":["Confirm Loki is actually up: curl http://<loki-host>:3100/ready until it returns 200 'ready'","Increase wait_for_ready in the Loki acquisition config","Fix the Loki URL/host/port in the acquisition yaml or DSN","If the probe is intentionally unwanted, set no_ready_check: true (errors will then surface later at read time)"],"exampleFix":"// before (acquisition yaml)\nwait_for_ready: 1s\n// after\nwait_for_ready: 30s","handlingStrategy":"retry","validationCode":"func lokiReady(baseURL string) error {\n    for i := 0; i < 30; i++ {\n        resp, err := http.Get(baseURL + \"/ready\")\n        if err == nil && resp.StatusCode == 200 {\n            resp.Body.Close()\n            return nil\n        }\n        if resp != nil { resp.Body.Close() }\n        time.Sleep(2 * time.Second)\n    }\n    return errors.New(\"loki /ready never returned 200\")\n}","typeGuard":null,"tryCatchPattern":"if err := src.OneShotAcquisition(ctx); err != nil {\n    if strings.Contains(err.Error(), \"loki is not ready\") {\n        // re-check /ready with backoff, then retry acquisition\n    }\n    return err\n}","preventionTips":["Health-check /ready before starting crowdsec","Set wait_for_ready larger than Loki's observed startup time","Use orchestration healthchecks/depends_on so Loki is ready first","Verify the DSN host/port with curl before deploying"],"tags":["loki","readiness","acquisition"],"backgroundTag":"upstream-api-error","analyzedSha":"909b5157986a2b2c2163300fdaef5ed01289f7d2","analyzedAt":"2026-09-06T12:27:26.012Z","contentChangedAt":"2026-09-06T12:27:26.012Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}