grpc/grpc-go · error

xds: failed to read bootstrap config from file %q: %v

Error message

xds: failed to read bootstrap config from file %q: %v

What it means

GetConfiguration reads the bootstrap file path from GRPC_XDS_BOOTSTRAP and attempts to os.ReadFile it (bootstrap.go:670-672). If the read itself fails (file does not exist, permission denied, I/O error), this error wraps the OS-level error with the filename so you know which path failed.

Source

Thrown at internal/xds/bootstrap/bootstrap.go:672

//
// This function tries to process as much of the bootstrap file as possible (in
// the presence of the errors) and may return a Config object with certain
// fields left unspecified, in which case the caller should use some sane
// defaults.
//
// This function returns an error if it's unable to parse the contents of the
// bootstrap config. It returns (nil, nil) if none of the env vars are set.
func GetConfiguration() (*Config, error) {
	fName := envconfig.XDSBootstrapFileName
	fContent := envconfig.XDSBootstrapFileContent

	if fName != "" {
		if logger.V(2) {
			logger.Infof("Using bootstrap file with name %q from GRPC_XDS_BOOTSTRAP environment variable", fName)
		}
		cfg, err := bootstrapFileReadFunc(fName)
		if err != nil {
			return nil, fmt.Errorf("xds: failed to read bootstrap config from file %q: %v", fName, err)
		}
		return NewConfigFromContents(cfg)
	}

	if fContent != "" {
		if logger.V(2) {
			logger.Infof("Using bootstrap contents from GRPC_XDS_BOOTSTRAP_CONFIG environment variable")
		}
		return NewConfigFromContents([]byte(fContent))
	}

	return nil, nil
}

// NewConfigFromContents creates a new bootstrap configuration from the provided
// contents.
func NewConfigFromContents(data []byte) (*Config, error) {
	// Normalize the input configuration.

View on GitHub (pinned to 03255a9237)

Solutions

  1. Verify the file exists and is readable: ls -l <path-from-GRPC_XDS_BOOTSTRAP> and run as the same UID.
  2. If running in Kubernetes, check that the ConfigMap/Secret volume mount and the env var path match exactly.
  3. Use an absolute path for GRPC_XDS_BOOTSTRAP to avoid working-directory ambiguity.
  4. Ensure the init container or sidecar that writes the bootstrap file completed successfully before the app container starts.

Example fix

# before: GRPC_XDS_BOOTSTRAP=/etc/grpc-xds/bootstrap.json but file missing
# after: mount the config and confirm
#   kubectl exec <pod> -- ls -l /etc/grpc-xds/bootstrap.json
Defensive patterns

Strategy: validation

Validate before calling

// Verify the bootstrap file is readable before GetConfiguration.
func ensureBootstrapFile(path string) error {
    info, err := os.Stat(path)
    if err != nil {
        return fmt.Errorf("bootstrap file %q: %w", path, err)
    }
    if info.IsDir() {
        return fmt.Errorf("bootstrap path %q is a directory", path)
    }
    return nil
}

Try / catch

// Wrap GetConfiguration and report the missing file clearly.
cfg, err := bootstrap.GetConfiguration()
if err != nil {
    return fmt.Errorf("cannot load xDS bootstrap from GRPC_XDS_BOOTSTRAP=%q: %w", os.Getenv("GRPC_XDS_BOOTSTRAP"), err)
}

Prevention

When it happens

Trigger: Thrown at internal/xds/bootstrap/bootstrap.go:672 when the library encounters an invalid state.

Common situations: Mount path mismatch in Kubernetes (the secret/configmap is mounted at a different path); the env var was set but the file creation step in the init container failed; running locally without copying the bootstrap file into the expected location; wrong relative path interpreted against an unexpected working directory.

Related errors


AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07). Data as JSON: /api/errors/842e10107a83f09e. Report an issue: GitHub.