wavetermdev/waveterm · error

error parsing token: %w

Error message

error parsing token: %w

What it means

ExtractUnverifiedRpcContext decodes a Wave JWT token into an RpcContext without verifying its signature. This error wraps any failure from jwt.Parser.ParseUnverified, meaning the token string could not be parsed as a JWT at all (malformed structure, wrong segment count, invalid base64 or JSON).

Source

Thrown at pkg/wshutil/wshutil.go:363

			conn.Close()
			close(proxy.FromRemoteCh)
			close(proxy.ToRemoteCh)
			linkId := linkIdContainer.Load()
			if linkId != baseds.NoLinkId {
				DefaultRouter.UnregisterLink(baseds.LinkId(linkId))
			}
		}()
		AdaptStreamToMsgCh(conn, proxy.FromRemoteCh, readCallback)
	}()
	linkId := DefaultRouter.RegisterUntrustedLink(proxy)
	linkIdContainer.Store(int32(linkId))
}

// only for use on client
func ExtractUnverifiedRpcContext(tokenStr string) (*wshrpc.RpcContext, error) {
	token, _, err := new(jwt.Parser).ParseUnverified(tokenStr, &wavejwt.WaveJwtClaims{})
	if err != nil {
		return nil, fmt.Errorf("error parsing token: %w", err)
	}
	claims, ok := token.Claims.(*wavejwt.WaveJwtClaims)
	if !ok {
		return nil, fmt.Errorf("error getting claims from token")
	}
	return claimsToRpcCtx(claims), nil
}

// only for use on client
func ExtractUnverifiedSocketName(tokenStr string) (string, error) {
	token, _, err := new(jwt.Parser).ParseUnverified(tokenStr, &wavejwt.WaveJwtClaims{})
	if err != nil {
		return "", fmt.Errorf("error parsing token: %w", err)
	}
	claims, ok := token.Claims.(*wavejwt.WaveJwtClaims)
	if !ok {
		return "", fmt.Errorf("error getting claims from token")
	}

View on GitHub (pinned to a4447c1563)

Solutions

  1. Regenerate the connection token from the running Wave server (wsh server) so the client reads a fresh, valid token
  2. Verify the string being passed is the JWT (three dot-separated base64 segments), not the socket name or another config value
  3. Inspect the wrapped inner error (%w) with errors.Unwrap to see the exact JWT parse failure (e.g. 'token contains an invalid number of segments')
  4. If the token comes from a file or env var, check for whitespace/newline corruption or truncation

Example fix

// before
ctx, err := wshutil.ExtractUnverifiedRpcContext(os.Getenv("WS_TOKEN"))
// after
tokenStr := strings.TrimSpace(os.Getenv("WS_TOKEN"))
if tokenStr == "" || strings.Count(tokenStr, ".") != 2 {
    return fmt.Errorf("invalid WSH token: regenerate via 'wsh server'")
}
ctx, err := wshutil.ExtractUnverifiedRpcContext(tokenStr)
Defensive patterns

Strategy: validation

Validate before calling

func looksLikeJwt(s string) bool {
    s = strings.TrimSpace(s)
    parts := strings.Split(s, ".")
    if len(parts) != 3 {
        return false
    }
    for _, p := range parts {
        if p == "" { return false }
        if _, err := base64.RawURLEncoding.DecodeString(p); err != nil { return false }
    }
    return true
}

Try / catch

ctx, err := wshutil.ExtractUnverifiedRpcContext(tokenStr)
if err != nil {
    return fmt.Errorf("invalid wsh token (regenerate with 'wsh server'): %w", err)
}

Prevention

When it happens

Trigger: Calling ExtractUnverifiedRpcContext with an empty string, a truncated or corrupted token, a token that is not a JWT (e.g. an opaque secret or a different token format), or a token whose claims JSON does not match wavejwt.WaveJwtClaims.

Common situations: Stale or hand-edited connection tokens in config; passing the wrong env/config value (e.g. the socket name instead of the token); tokens regenerated by a newer server version while an old client reads cached ones; shell quoting mangling the token on the command line.

Related errors


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/3404b503c625b6dc. Report an issue: GitHub.