{"record":{"id":"f15803157b9bba20","repo":"coollabsio/coolify","slug":"no-digitalocean-token-found-for-the-server-team","errorCode":null,"errorMessage":"No DigitalOcean token found for the server team.","messagePattern":"No DigitalOcean token found for the server team\\.","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"app/Actions/Server/DeleteServer.php","lineNumber":165,"sourceCode":"    {\n        try {\n            $token = null;\n\n            if ($cloudProviderTokenId) {\n                $token = CloudProviderToken::where('id', $cloudProviderTokenId)\n                    ->where('team_id', $teamId)\n                    ->where('provider', 'digitalocean')\n                    ->first();\n            }\n\n            if (! $token) {\n                $token = CloudProviderToken::where('team_id', $teamId)\n                    ->where('provider', 'digitalocean')\n                    ->first();\n            }\n\n            if (! $token) {\n                throw new \\RuntimeException('No DigitalOcean token found for the server team.');\n            }\n\n            $digitalOceanService = new DigitalOceanService($token->token);\n            $digitalOceanService->deleteDroplet($digitalOceanDropletId);\n\n            logger()->debug('Deleted droplet from DigitalOcean', [\n                'digitalocean_droplet_id' => $digitalOceanDropletId,\n                'team_id' => $teamId,\n            ]);\n        } catch (\\Throwable $e) {\n            logger()->error('Failed to delete droplet from DigitalOcean', [\n                'error' => $e->getMessage(),\n                'digitalocean_droplet_id' => $digitalOceanDropletId,\n                'team_id' => $teamId,\n            ]);\n\n            throw $e;\n        }","sourceCodeStart":147,"sourceCodeEnd":183,"githubUrl":"https://github.com/coollabsio/coolify/blob/70b9acc42467278373e00de77abb40684e25b395/app/Actions/Server/DeleteServer.php#L147-L183","documentation":"DigitalOcean twin of the Vultr error: DeleteServer::deleteFromDigitalOceanById() throws this RuntimeException when deleteFromDigitalOcean=true (or the server has digitalocean_droplet_id with provider deletion enabled) and no CloudProviderToken with provider='digitalocean' can be resolved — first via the passed cloudProviderTokenId, then via any team-owned DigitalOcean token. The catch block logs and re-throws, so the Coolify-side server deletion (forceDelete) never runs.","triggerScenarios":"Deleting a DigitalOcean-linked server when the team's DO token was deleted, when cloudProviderTokenId references a token of the wrong provider or wrong team, or when the server row's team_id differs from the token owner after re-organization.","commonSituations":"DO token rotated/deleted after droplet creation; multiple teams where the token lives in another team; API automation passing deleteFromDigitalOcean without a token id.","solutions":["Re-add a DigitalOcean provider token for the server's team so the fallback token lookup succeeds.","Pass an explicit, valid cloudProviderTokenId (provider='digitalocean', matching team_id) when dispatching DeleteServer.","If the droplet was already destroyed manually, delete the server without deleteFromDigitalOcean.","Programmatically: catch the RuntimeException (log + notify) and continue Coolify-side deletion if provider cleanup is best-effort."],"exampleFix":"// before\nDeleteServer::run($serverId, deleteFromDigitalOcean: true,\n    digitalOceanDropletId: $server->digitalocean_droplet_id);\n\n// after\n$hasToken = CloudProviderToken::where('team_id', $server->team_id)\n    ->where('provider', 'digitalocean')->exists();\nDeleteServer::run($serverId,\n    deleteFromDigitalOcean: $hasToken,\n    digitalOceanDropletId: $server->digitalocean_droplet_id);","handlingStrategy":"validation","validationCode":"$hasDoToken = \\App\\Models\\CloudProviderToken::query()\n    ->where('team_id', $server->team_id)\n    ->where('provider', 'digitalocean')\n    ->exists();\nif (! $hasDoToken) {\n    return back()->withErrors(['server' => 'Add a DigitalOcean token for this team before deleting the server from DigitalOcean.']);\n}\n\\App\\Actions\\Server\\DeleteServer::run($server->id, deleteFromDigitalOcean: true, digitalOceanDropletId: $server->digitalocean_droplet_id);","typeGuard":"function teamHasDigitalOceanToken(int $teamId): bool\n{\n    return \\App\\Models\\CloudProviderToken::query()\n        ->where('team_id', $teamId)\n        ->where('provider', 'digitalocean')\n        ->exists();\n}","tryCatchPattern":"try {\n    DeleteServer::run($serverId, deleteFromDigitalOcean: true, digitalOceanDropletId: $dropletId);\n} catch (\\RuntimeException $e) {\n    if (str_contains($e->getMessage(), 'No DigitalOcean token found')) {\n        report($e); // ask user to re-link token; do not auto-retry\n    } else {\n        throw $e;\n    }\n}","preventionTips":["Maintain a DigitalOcean token per team that owns DO-linked servers.","Pass cloudProviderTokenId explicitly in automated deletion flows.","Disable the 'delete from provider' option in the UI when the team lacks a matching token.","Watch the logs: the action logs 'Failed to delete droplet from DigitalOcean' before re-throwing — monitor that channel."],"tags":["digitalocean","cloud-provider-token","server-deletion","api-token","team"],"backgroundTag":"missing-cloud-provider-token","analyzedSha":"70b9acc42467278373e00de77abb40684e25b395","analyzedAt":"2026-08-17T01:41:01.313Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}