wavetermdev/waveterm · error
error decoding jwt public key: %w
Error message
error decoding jwt public key: %w
What it means
Identical to the private-key case but for MainServer.JwtPublicKey: InitMainServer base64-decodes the stored public key and wraps any DecodeString failure. A non-standard-base64 or corrupt public key aborts startup.
Source
Thrown at pkg/wcore/wcore.go:205
mainServer.JwtPrivateKey = base64.StdEncoding.EncodeToString(keyPair.PrivateKey)
mainServer.JwtPublicKey = base64.StdEncoding.EncodeToString(keyPair.PublicKey)
needsUpdate = true
}
if needsUpdate {
err = wstore.DBUpdate(ctx, mainServer)
if err != nil {
return fmt.Errorf("error updating mainserver: %w", err)
}
}
privateKeyBytes, err := base64.StdEncoding.DecodeString(mainServer.JwtPrivateKey)
if err != nil {
return fmt.Errorf("error decoding jwt private key: %w", err)
}
publicKeyBytes, err := base64.StdEncoding.DecodeString(mainServer.JwtPublicKey)
if err != nil {
return fmt.Errorf("error decoding jwt public key: %w", err)
}
err = wavejwt.SetPrivateKey(privateKeyBytes)
if err != nil {
return fmt.Errorf("error setting jwt private key: %w", err)
}
err = wavejwt.SetPublicKey(publicKeyBytes)
if err != nil {
return fmt.Errorf("error setting jwt public key: %w", err)
}
pubKeyDer, err := x509.MarshalPKIXPublicKey(ed25519.PublicKey(publicKeyBytes))
if err != nil {
log.Printf("warning: could not marshal public key for logging: %v", err)
} else {
pubKeyPem := pem.EncodeToMemory(&pem.Block{
Type: "PUBLIC KEY",
Bytes: pubKeyDer,View on GitHub (pinned to a4447c1563)
Solutions
- Clear the Jwt* fields (or delete the singleton/DB) so a fresh key pair is generated on next start
- Re-encode the public key with base64.StdEncoding and store it back
- Check for and remove newlines/whitespace in the stored value
- Validate the decoded length: an ed25519 public key must decode to exactly 32 bytes
Example fix
// sanity check before restart
b, err := base64.StdEncoding.DecodeString(mainServer.JwtPublicKey)
if err != nil || len(b) != ed25519.PublicKeySize {
mainServer.JwtPublicKey = "" // force regeneration
} Defensive patterns
Strategy: validation
Validate before calling
if _, err := base64.StdEncoding.DecodeString(mainServer.JwtPublicKey); err != nil {
mainServer.JwtPublicKey = "" // force regeneration path
} Type guard
func isValidEd25519PubB64(s string) bool {
b, err := base64.StdEncoding.DecodeString(s)
return err == nil && len(b) == ed25519.PublicKeySize
} Try / catch
if err := wcore.InitMainServer(); err != nil {
if strings.Contains(err.Error(), "decoding jwt public key") {
clearJwtKeysInDB()
return wcore.InitMainServer()
}
panic(err)
} Prevention
- Validate decoded public key is exactly 32 bytes before storing
- Do not copy keys through editors that wrap/insert newlines
- Use StdEncoding consistently, never URLEncoding, for stored keys
- Clear both key fields together when regenerating
When it happens
Trigger: base64.StdEncoding.DecodeString(mainServer.JwtPublicKey) returns an error — the DB value is not valid standard base64 (wrong encoding variant, truncation, whitespace, manual edit, or interrupted write).
Common situations: Hand-edited or copy-pasted key values; restoring a truncated DB backup; version differences in how keys were serialized.
Related errors
- error decoding jwt private key: %w
- error decoding jwt public key: %v
- error setting jwt public key: %v
- failed to set public key: %w
- error setting jwt public key: %w
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/fb5ab648ffa234a4.
Report an issue: GitHub.