slackhq/nebula · critical

no certificate state

Error message

no certificate state

What it means

Configuration guard in NewInterface: InterfaceConfig.pki is nil, meaning no certificate/PKI state was built (e.g. pki config missing or failed to load). The interface cannot handshake or encrypt without certificates, so construction aborts.

Solutions

  1. Verify pki.cert, pki.key and pki.ca paths in config point to valid, readable files
  2. Check earlier logs for certificate parse/load errors
  3. Regenerate or reissue expired/invalid certificates with nebula-cert
  4. Ensure the pki section is present and correctly structured in the config
Defensive patterns

Strategy: validation

Validate before calling

if cfg.InterfaceConfig.Pki == nil {
    return errors.New("pki not loaded; check cert/key/ca paths")
}
// also verify upfront:
_, err := pki.NewPKIFromConfig(cfg.Pki) // fails fast on bad cert paths/parse errors

Try / catch

i, err := NewInterface(ctx, c)
if err != nil {
    if err.Error() == "no certificate state" { /* fix pki config / regenerate certs */ }
    return err
}

Prevention

When it happens

Trigger: InterfaceConfig.pki is nil because certificate loading (ca pool + own cert/key) failed or was skipped in Main before interface creation.

Common situations: Bad cert/key file paths in config; unparseable or expired certificates; missing 'pki' config section; YAML/JSON struct not mapped when embedding nebula.

Understand the failure class

Background: "X is required", "must be set", "cannot be empty": the missing-required-config error family, from Vertex AI project/location to WeChat keys — this error's family across 18 libraries.

Related errors


AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03). Data as JSON: /api/errors/72794fa2e6a086e5. Report an issue: GitHub.

Appendix: source

Thrown at interface.go:192

		return "always"
	case recvErrorNever:
		return "never"
	case recvErrorPrivate:
		return "private"
	default:
		return fmt.Sprintf("invalid(%d)", s)
	}
}

func NewInterface(ctx context.Context, c *InterfaceConfig) (*Interface, error) {
	if c.Outside == nil {
		return nil, errors.New("no outside connection")
	}
	if c.Inside == nil {
		return nil, errors.New("no inside interface (tun)")
	}
	if c.pki == nil {
		return nil, errors.New("no certificate state")
	}
	if c.Firewall == nil {
		return nil, errors.New("no firewall rules")
	}
	if c.connectionManager == nil {
		return nil, errors.New("no connection manager")
	}

	if c.routines <= 1 {
		c.PinThreads = false //pinning is not useful unless there's more than one tun reader
	}

	cs := c.pki.getCertState()
	ifce := &Interface{
		ctx:                   ctx,
		pki:                   c.pki,
		hostMap:               c.HostMap,
		outside:               c.Outside,

View on GitHub (pinned to dd8f660c0a)