kubernetes/kops · error

failed to stop server

Error message

failed to stop server %q: %w

What it means

deleteServer issues a graceful Shutdown via the Hetzner API before deletion; this error is thrown when the Shutdown call itself returns an error from the Hetzner Cloud API. The server is left running and deletion aborts.

Solutions

  1. Check whether the server still exists (hcloud CLI / console); treat 404 as already deleted
  2. Verify the API token has write permission on servers
  3. Retry the deletion after transient errors; check for concurrent kOps processes
  4. Inspect the wrapped hcloud error code for the precise cause

Example fix

// before
if err != nil {
	return fmt.Errorf("failed to stop server %q: %w", strconv.FormatInt(id, 10), err)
}
// after
if err != nil {
	if hcloud.IsError(err, hcloud.ErrorCodeNotFound) {
		return nil // already deleted
	}
	return fmt.Errorf("failed to stop server %q: %w", strconv.FormatInt(id, 10), err)
}
Defensive patterns

Strategy: retry

Validate before calling

server, _, err := client.GetByID(ctx, id)
if server == nil {
	return nil // server already gone; skip shutdown/delete
}

Type guard

func serverExists(client *hcloud.ServerClient, id int64) bool {
	s, _, err := client.GetByID(context.TODO(), id)
	return err == nil && s != nil
}

Try / catch

err := deleteServer(c, id)
if err != nil {
	var hErr *hcloud.Error
	if errors.As(err, &hErr) && hErr.Code == hcloud.ErrorCodeNotFound {
		return nil
	}
	return err
}

Prevention

When it happens

Trigger: Calling DeleteInstance/DeleteGroup -> deleteServer when the server no longer exists (404 not_found), the API token lacks permission, the request times out, or the API is rate-limited/unavailable.

Common situations: Attempting to delete an already-removed server (e.g. manually deleted in Hetzner console or concurrent kOps run), token scope changes, or transient API failures during rolling updates.

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/1acdf21be29b54c7. Report an issue: GitHub.

Appendix: source

Thrown at upup/pkg/fi/cloudup/hetzner/cloud.go:270

	serverID, err := strconv.ParseInt(instance.ID, 10, 64)
	if err != nil {
		return fmt.Errorf("failed to convert server ID %q to int: %w", instance.ID, err)
	}

	err = deleteServer(c, serverID)

	return err
}

// deleteServer shuts down and deletes the given server
func deleteServer(c *hetznerCloudImplementation, id int64) error {
	client := c.ServerClient()
	ctx := context.TODO()

	server := &hcloud.Server{ID: id}
	_, _, err := client.Shutdown(ctx, server)
	if err != nil {
		return fmt.Errorf("failed to stop server %q: %w", strconv.FormatInt(id, 10), err)
	}

	for i := 1; i <= 30; i++ {
		server, _, err := client.GetByID(ctx, id)
		if err != nil || server == nil {
			return fmt.Errorf("failed to get info for server %q: %w", strconv.FormatInt(id, 10), err)
		}

		if server.Status == hcloud.ServerStatusOff {
			break
		}

		time.Sleep(time.Second * 5)
	}

	_, err = client.Delete(ctx, server)
	if err != nil {
		return fmt.Errorf("failed to delete server %q: %w", strconv.FormatInt(id, 10), err)

View on GitHub (pinned to 4c8573c808)