wavetermdev/waveterm · error

error marshalling message to json: %w

Error message

error marshalling message to json: %w

What it means

EncodeWaveOSCMessageEx marshals the RpcMessage to JSON before OSC encoding. This error wraps a json.Marshal failure, which happens when the message contains data that cannot be serialized — most commonly unsupported types (channels, funcs) placed in the Data field, or a custom MarshalJSON that errors.

Source

Thrown at pkg/wshutil/wshutil.go:121

		if b < 0x20 || b == 0x7f {
			escSeq[4] = HexChars[b>>4]
			escSeq[5] = HexChars[b&0x0f]
			buf.Write(escSeq[:])
		} else {
			buf.WriteByte(b)
		}
	}
	buf.WriteByte(BEL)
	return buf.Bytes(), nil
}

func EncodeWaveOSCMessageEx(oscNum string, msg *RpcMessage) ([]byte, error) {
	if msg == nil {
		return nil, fmt.Errorf("nil message")
	}
	barr, err := json.Marshal(msg)
	if err != nil {
		return nil, fmt.Errorf("error marshalling message to json: %w", err)
	}
	return EncodeWaveOSCBytes(oscNum, barr)
}

var shutdownOnce sync.Once

func DoShutdown(reason string, exitCode int, quiet bool) {
	shutdownOnce.Do(func() {
		defer os.Exit(exitCode)
		if !quiet && reason != "" {
			log.Printf("shutting down: %s\n", reason)
		}
	})
}

func SetupPacketRpcClient(input io.Reader, output io.Writer, serverImpl ServerImpl, debugStr string) (*WshRpc, chan []byte) {
	messageCh := make(chan baseds.RpcInputChType, DefaultInputChSize)
	outputCh := make(chan []byte, DefaultOutputChSize)

View on GitHub (pinned to a4447c1563)

Solutions

  1. Inspect the wrapped %w error to find the offending field/type.
  2. Ensure Data contains only JSON-safe values (maps, slices, strings, numbers, bools).
  3. Add a serialization smoke test for message builders.
  4. Marshal the payload yourself earlier to surface the bad field with better context.

Example fix

// before
msg := &RpcMessage{Data: func() {}} // unserializable
barr, err := EncodeWaveOSCMessageEx("1337;", msg)
// after
msg := &RpcMessage{Data: map[string]any{"result": serializedResult}}
barr, err := EncodeWaveOSCMessageEx("1337;", msg)
Defensive patterns

Strategy: validation

Validate before calling

if _, err := json.Marshal(msg); err != nil {
    return fmt.Errorf("message not JSON-serializable: %w", err)
}

Try / catch

if _, err := EncodeWaveOSCMessageEx(oscNum, msg); err != nil {
    var uerr *json.UnsupportedTypeError
    if errors.As(err, &uerr) {
        log.Printf("unsupported field type: %v", uerr.Value)
    }
    return err
}

Prevention

When it happens

Trigger: json.Marshal(msg) fails for an *RpcMessage whose payload (e.g. Data as any) holds unserializable values like func, chan, cycle references, or a type with a failing MarshalJSON.

Common situations: Storing a callback or Go-specific value in the loosely-typed Data field; cyclic object graphs; incompatible types after a struct refactor.

Understand the failure class

Background: "JSON serialization failed", "not JSON serializable", "Failed to serialize": why JSON marshaling errors happen and how to fix them — this error's family across 46 libraries.

Related errors


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