netbirdio/netbird · error
one of SetupKey, JWTToken, or PrivateKey must be provided
Error message
one of SetupKey, JWTToken, or PrivateKey must be provided
What it means
embed.Options.validateCredentials requires exactly one registration credential for the embedded client (client/embed): SetupKey, JWTToken, or PrivateKey. This is the zero-credential case — the counter never incremented, so New() aborts before creating the client. The embedded client has no interactive SSO fallback, hence the hard requirement.
Source
Thrown at client/embed/embed.go:140
// only; ignored by Client.SetPerformance.
MaxBatchSize *uint32
}
// validateCredentials checks that exactly one credential type is provided
func (opts *Options) validateCredentials() error {
credentialsProvided := 0
if opts.SetupKey != "" {
credentialsProvided++
}
if opts.JWTToken != "" {
credentialsProvided++
}
if opts.PrivateKey != "" {
credentialsProvided++
}
if credentialsProvided == 0 {
return fmt.Errorf("one of SetupKey, JWTToken, or PrivateKey must be provided")
}
if credentialsProvided > 1 {
return fmt.Errorf("only one of SetupKey, JWTToken, or PrivateKey can be specified")
}
return nil
}
// New creates a new netbird embedded client.
func New(opts Options) (*Client, error) {
if err := opts.validateCredentials(); err != nil {
return nil, err
}
if opts.MTU != nil {
if err := iface.ValidateMTU(*opts.MTU); err != nil {
return nil, fmt.Errorf("invalid MTU: %w", err)
}View on GitHub (pinned to 93e97f4bf1)
Solutions
- Provide a setup key: opts.SetupKey = "AAAA..."
- Or provide a JWT token obtained out-of-band: opts.JWTToken = token
- Or provide the peer private key for re-registration: opts.PrivateKey = key
Example fix
// before
client, err := embed.New(embed.Options{ManagementURL: "https://mgr"}) // err: one of SetupKey, JWTToken, or PrivateKey must be provided
// after
client, err := embed.New(embed.Options{
ManagementURL: "https://mgr",
SetupKey: os.Getenv("NETBIRD_SETUP_KEY"),
}) Defensive patterns
Strategy: type-guard
Type guard
func hasExactlyOneCredential(o embed.Options) error {
n := 0
for _, c := range []string{o.SetupKey, o.JWTToken, o.PrivateKey} {
if c != "" {
n++
}
}
if n != 1 {
return fmt.Errorf("got %d credentials, want exactly 1", n)
}
return nil
} Try / catch
if _, err := embed.New(opts); err != nil {
if strings.Contains(err.Error(), "must be provided") {
// credential wiring bug, not transient: fetch a setup key and rebuild opts
}
} Prevention
- Fail fast in config loading if no credential source is configured
- Remember the embedded client has no interactive SSO; always provision a credential
When it happens
Trigger: Calling embed.New(embed.Options{...}) without setting any of the three credential fields, e.g. intending interactive login which the embedded build does not support.
Common situations: Porting CLI-style usage (where `netbird up` can prompt for SSO) into the embedded library, or forgetting to wire the credential from the environment into Options.
Related errors
- only one of SetupKey, JWTToken, or PrivateKey can be specifi
- connector type change not allowed
- service name is required
- service name exceeds maximum length of 255 characters
- at least one target is required
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/035f8918c8e950fb.
Report an issue: GitHub.