gravitational/teleport · info

all fetched nodes already enrolled

Error message

all fetched nodes already enrolled

What it means

errNoInstances is a sentinel error returned by the discovery service's GCP instance handler when the watcher delivers an Instances batch whose Instances list is empty. It is not a failure: it signals that all discovered GCP VMs were filtered out (already enrolled or not matching matchers). Callers check errors.Is(err, errNoInstances) and log at debug level instead of treating it as an error.

Source

Thrown at lib/srv/discovery/discovery.go:84

	"github.com/gravitational/teleport/lib/cryptosuites"
	"github.com/gravitational/teleport/lib/services"
	"github.com/gravitational/teleport/lib/services/readonly"
	"github.com/gravitational/teleport/lib/srv/discovery/common"
	"github.com/gravitational/teleport/lib/srv/discovery/fetchers"
	aws_sync "github.com/gravitational/teleport/lib/srv/discovery/fetchers/aws-sync"
	azure_sync "github.com/gravitational/teleport/lib/srv/discovery/fetchers/azuresync"
	"github.com/gravitational/teleport/lib/srv/discovery/fetchers/db"
	"github.com/gravitational/teleport/lib/srv/server"
	"github.com/gravitational/teleport/lib/utils"
	"github.com/gravitational/teleport/lib/utils/aws/iamutils"
	liborganizations "github.com/gravitational/teleport/lib/utils/aws/organizations"
	"github.com/gravitational/teleport/lib/utils/aws/stsutils"
	logutils "github.com/gravitational/teleport/lib/utils/log"
	libslices "github.com/gravitational/teleport/lib/utils/slices"
	"github.com/gravitational/teleport/lib/utils/spreadwork"
)

var errNoInstances = errors.New("all fetched nodes already enrolled")

const noDiscoveryConfig = ""

// Matchers contains all matchers used by discovery service
type Matchers struct {
	// AWS is a list of AWS EC2 matchers.
	AWS []types.AWSMatcher
	// Azure is a list of Azure matchers to discover resources.
	Azure []types.AzureMatcher
	// GCP is a list of GCP matchers to discover resources.
	GCP []types.GCPMatcher
	// Kubernetes is a list of Kubernetes matchers to discovery resources.
	Kubernetes []types.KubernetesMatcher
	// AccessGraph is the configuration for the Access Graph Cloud sync.
	AccessGraph *types.AccessGraphSync
}

func (m Matchers) IsEmpty() bool {

View on GitHub (pinned to 1283425b60)

Solutions

  1. No action needed if expected — this is informational; discovery will retry on the next poll
  2. Check discovery matchers (labels, zones, project IDs) if you expected VMs to be discovered
  3. Verify the VMs are not already enrolled in the cluster under different names
Defensive patterns

Strategy: type-guard

Validate before calling

if instances == nil || len(instances.Instances) == 0 {
    log.DebugContext(ctx, "no new GCP instances to enroll")
    return nil
}

Type guard

func hasInstances(in *inventory.Instances) bool { return in != nil && len(in.Instances) > 0 }

Try / catch

if err := s.handleGCPInstances(instances); err != nil {
    if errors.Is(err, errNoInstances) {
        s.Log.DebugContext(s.ctx, "All discovered GCP VMs are already part of the cluster")
        return nil
    }
    return trace.Wrap(err)
}

Prevention

When it happens

Trigger: handleGCPInstances receives a GCP instances fetch result where len(instances.Instances) == 0 — the GCP watcher poll returned no new VMs after filtering against cluster membership.

Common situations: Periodic GCP VM discovery poll where all VMs are already enrolled; over-restrictive discovery matchers filtering out every VM; GCP project/zone with no instances.

Related errors


AI-assisted analysis of gravitational/teleport@1283425b60 (2026-09-02). Data as JSON: /api/errors/12f3635fc82bdece. Report an issue: GitHub.