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
- No action needed if expected — this is informational; discovery will retry on the next poll
- Check discovery matchers (labels, zones, project IDs) if you expected VMs to be discovered
- 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
- Treat empty discovery batches as normal periodic-poll outcomes
- Log empty results at debug level, not error
- Review matchers if empty results are unexpected
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.