wavetermdev/waveterm · error

error re-marshalling command data: %w

Error message

error re-marshalling command data: %w

What it means

After resolving the command's declared type, recodeCommandData round-trips the payload (utilfn.ReUnmarshal: marshal to JSON then unmarshal into the declared type pointer). If the payload cannot be converted into the declared command data type, this wrapped error is returned. It is a payload-shape mismatch, not a transport failure.

Source

Thrown at pkg/wshutil/wshadapter.go:69

func noImplHandler(handler *RpcResponseHandler) bool {
	handler.SendResponseError(fmt.Errorf("command %q not implemented", handler.GetCommand()))
	return true
}

func recodeCommandData(command string, data any, commandDataType reflect.Type) (any, error) {
	if command == "" || commandDataType == nil {
		return data, nil
	}
	methodDecl := WshCommandDeclMap[command]
	if methodDecl == nil {
		return data, fmt.Errorf("command %q not found", command)
	}
	commandDataPtr := reflect.New(commandDataType).Interface()
	if data != nil {
		err := utilfn.ReUnmarshal(commandDataPtr, data)
		if err != nil {
			return data, fmt.Errorf("error re-marshalling command data: %w", err)
		}
	}
	return reflect.ValueOf(commandDataPtr).Elem().Interface(), nil
}

func serverImplAdapter(impl any) func(*RpcResponseHandler) bool {
	if impl == nil {
		return noImplHandler
	}
	rtype := reflect.TypeOf(impl)
	if rtype.Kind() != reflect.Ptr && rtype.Elem().Kind() != reflect.Struct {
		panic(fmt.Sprintf("expected struct pointer, got %s", rtype))
	}
	// returns isAsync
	return func(handler *RpcResponseHandler) bool {
		cmd := handler.GetCommand()
		methodDecl := WshCommandDeclMap[cmd]
		if methodDecl == nil {

View on GitHub (pinned to a4447c1563)

Solutions

  1. Read the wrapped inner error to see which JSON field/type failed, then reshape your payload to match the command's declared data struct in pkg/wshrpc.
  2. Construct the proper typed struct (e.g. wshrpc.CommandVarData{...}) instead of an ad-hoc map or string.
  3. If both sides are your code, update the client and server together so the payload schema matches the declaration.

Example fix

// before: string payload for a struct command
data := "/home/user/.zshrc"
// after: typed payload
path, _ := homedir.ExpandHome("~/.zshrc")
data := wshrpc.CommandFileData{Info: &wshrpc.FileInfo{Path: path}}
Defensive patterns

Strategy: type-guard

Validate before calling

// Validate payload marshals and fits the declared struct before sending
b, err := json.Marshal(payload)
if err != nil { return err }
typed := wshrpc.CommandVarData{}
if err := json.Unmarshal(b, &typed); err != nil {
    return fmt.Errorf("payload does not match declared type: %w", err)
}

Type guard

func isCommandData[T any](data any) bool {
    var zero T
    b, err := json.Marshal(data)
    if err != nil { return false }
    return json.Unmarshal(b, &zero) == nil
}

Try / catch

_, err := client.SendRpcRequest(ctx, cmd, data)
var reErr *fmt.Errorf
if err != nil && errors.As(err, &reErr) && strings.Contains(err.Error(), "re-marshalling command data") {
    log.Printf("payload shape mismatch for %s: %v", cmd, err)
    return fmt.Errorf("invalid payload for %s: %w", cmd, err)
}

Prevention

When it happens

Trigger: Calling an RPC with data whose JSON shape does not fit the command's declared data struct: wrong field names (Go unmarshal is case-insensitive but incompatible types fail), a string where a number is expected, an object where an array is expected, or data that is not JSON-marshalable.

Common situations: Sending a bare value when the command expects a struct like CommandVarData; version skew where a field's type changed between releases; scripts passing shell-style strings to typed commands.

Related errors


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