{"record":{"id":"443885afaf6cd069","repo":"wtfutil/wtf","slug":"client-could-not-be-initialized","errorCode":null,"errorMessage":"client could not be initialized","messagePattern":"client could not be initialized","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/digitalocean/widget.go","lineNumber":70,"sourceCode":"\t}\n\n\twidget.initializeKeyboardControls()\n\n\twidget.View.SetScrollable(true)\n\n\twidget.SetRenderFunction(widget.display)\n\n\twidget.createClient()\n\n\treturn &widget\n}\n\n/* -------------------- Exported Functions -------------------- */\n\n// Fetch retrieves droplet data\nfunc (widget *Widget) Fetch() error {\n\tif widget.client == nil {\n\t\treturn errors.New(\"client could not be initialized\")\n\t}\n\n\tvar err error\n\twidget.droplets, err = widget.dropletsFetch()\n\treturn err\n}\n\n// Next selects the next item in the list\nfunc (widget *Widget) Next() {\n\twidget.ScrollableWidget.Next()\n}\n\n// Prev selects the previous item in the list\nfunc (widget *Widget) Prev() {\n\twidget.ScrollableWidget.Prev()\n}\n\n// Refresh updates the data for this widget and displays it onscreen","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/wtfutil/wtf/blob/bb838c1ccb0f0f3223690df44afdec663d622881/modules/digitalocean/widget.go#L52-L88","documentation":"digitalocean widget.Fetch() requires a configured DigitalOcean API client (widget.client). If client initialization failed earlier (typically a missing or invalid DIGITALOCEAN_ACCESS_TOKEN), client stays nil and Fetch returns this error instead of dereferencing nil. The widget has no droplet client to query with.","triggerScenarios":"Widget loaded without an access token env var set; token rejected/empty at NewClient time so widget.client was never assigned; Fetch() or Refresh()/fetchAndDisplayEvents() invoked before successful client setup.","commonSituations":"DIGITALOCEAN_ACCESS_TOKEN missing from the environment wtfutil runs in (systemd/launchd don't inherit your shell env); expired or revoked API token; typo'd env var name in config.yml.","solutions":["Export DIGITALOCEAN_ACCESS_TOKEN with a valid read-scoped token in the environment wtfutil launches from","Check the widget's token configuration in config.yml matches the expected env var name","Regenerate the token in the DigitalOcean console if it was revoked/expired","Verify client construction logs — fix the initialization error that left client nil"],"exampleFix":"// before (systemd unit, no env)\nExecStart=/usr/local/bin/wtfutil\n// after\nExecStart=/usr/local/bin/wtfutil\nEnvironment=DIGITALOCEAN_ACCESS_TOKEN=dop_v1_xxxx","handlingStrategy":"validation","validationCode":"if os.Getenv(\"DIGITALOCEAN_ACCESS_TOKEN\") == \"\" {\n    return errors.New(\"DIGITALOCEAN_ACCESS_TOKEN must be set\")\n}","typeGuard":"func clientReady(w *Widget) bool { return w != nil && w.client != nil }","tryCatchPattern":"if err := widget.Fetch(); err != nil {\n    if err.Error() == \"client could not be initialized\" {\n        log.Print(\"check DIGITALOCEAN_ACCESS_TOKEN and client setup\")\n        return\n    }\n    return err\n}","preventionTips":["Verify the token env var in the exact environment wtfutil launches from (systemd/launchd need Environment= lines)","Log client-construction errors instead of silently leaving client nil","Use a read-scoped personal access token","Add a startup health check that calls Fetch once and reports the error"],"tags":["go","api-client","digitalocean","config"],"backgroundTag":"api-client-not-initialized","analyzedSha":"bb838c1ccb0f0f3223690df44afdec663d622881","analyzedAt":"2026-09-03T17:02:45.030Z","contentChangedAt":"2026-09-03T17:02:45.030Z","schemaVersion":2},"datasetVersion":"2026-09-11T00:17:11.886Z"}