grpc/grpc-go · error

xds: failed to read bootstrap config from file

Error message

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

What it means

Returned by GetConfiguration when os.ReadFile of the bootstrap file path fails. The path comes from GRPC_XDS_BOOTSTRAP (or the envconfig override). The underlying OS error (not exist, permission denied, etc.) is wrapped.

Solutions

  1. Confirm GRPC_XDS_BOOTSTRAP is set and the path exists: ls -l $GRPC_XDS_BOOTSTRAP.
  2. In containers/k8s, ensure the ConfigMap/secret holding the bootstrap is mounted at that path.
  3. Check read permissions for the process's UID/GID.
  4. Use an absolute path to avoid working-directory ambiguity.

Example fix

# before
export GRPC_XDS_BOOTSTRAP=/etc/grpc-bootstrap.json  # file absent

# after
export GRPC_XDS_BOOTSTRAP=/etc/grpc-xds/bootstrap.json
ls -l /etc/grpc-xds/bootstrap.json
Defensive patterns

Strategy: validation

Validate before calling

// Startup readiness check for the bootstrap file.
func checkBootstrapFile(path string) error {
    fi, err := os.Stat(path)
    if err != nil {
        return fmt.Errorf("bootstrap file: %w", err)
    }
    if fi.Size() == 0 {
        return fmt.Errorf("bootstrap file is empty")
    }
    return nil
}

Try / catch

if _, err := bootstrap.GetConfiguration(); err != nil {
    if strings.Contains(err.Error(), "failed to read bootstrap config from file") {
        // fix GRPC_XDS_BOOTSTRAP path/permissions, then restart.
    }
}

Prevention

When it happens

Trigger: Triggered at bootstrap.go:672 when bootstrapFileReadFunc(fName) (os.ReadFile) errors. The file does not exist, is not readable, or the path is wrong.

Common situations: GRPC_XDS_BOOTSTRAP points to a missing path; in a container the bootstrap file was not mounted/copied; file permissions deny the process; relative path resolved against an unexpected working directory.

Related errors


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

Appendix: 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 0c51461d27)