chenhg5/cc-connect · warning

wps-agentspace: parse message: %w

Error message

wps-agentspace: parse message: %w

What it means

If the JSON payload of an incoming "message" frame cannot be unmarshaled into messageData, handleFrame returns "wps-agentspace: parse message: %w". readLoop logs it via slog.Error and continues the loop, so this does not kill the connection — the offending frame is simply dropped. It indicates the server sent a message body that does not match the client's expected schema.

Source

Thrown at platform/wps-agentspace/wpsagentspace.go:525

				"USER_NO_APP_PERMISSION",
				"USER_NO_OPENCLAW_PERMISSION",
				"OPENCLAW_NOT_CONFIGURED",
				"NOT_OPENCLAW_APP",
				"NOT_LOGIN",
			}
			for _, code := range fatalCodes {
				if data.Code == code {
					return fmt.Errorf("wps-agentspace: fatal error: %s", data.Code)
				}
			}
			slog.Warn("wps-agentspace: server error", "code", data.Code)
		}
		return nil

	case "message":
		var data messageData
		if err := json.Unmarshal(frame.Data, &data); err != nil {
			return fmt.Errorf("wps-agentspace: parse message: %w", err)
		}
		slog.Debug("wps-agentspace: message frame", "role", data.Role, "type", data.Type, "content_len", len(data.Content))
		if data.Role == "user" {
			return p.handleUserMessage(data)
		}
		return nil

	default:
		return nil
	}
}

// handleUserMessage processes an incoming user message.
func (p *Platform) handleUserMessage(data messageData) error {
	chatID := data.SessionID
	if chatID == "" {
		chatID = data.ChatID
	}

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Check the wrapped unmarshal error to see which field/type mismatched
  2. Upgrade cc-connect to a version matching the current AgentSpace v7 message schema
  3. Compare the raw frame (visible in the debug log line "received frame") against the messageData struct and adjust the struct tags if you build from source
  4. If caused by a proxy/test mock, fix the frame producer to emit the documented schema

Example fix

// before
type messageData struct {
	Timestamp int64  `json:"timestamp"`
	Content   string `json:"content"`
}
// after — tolerate a server that sends timestamp as string
func (d *messageData) UnmarshalJSON(b []byte) error {
	type alias messageData
	var raw struct {
		alias
		Timestamp any `json:"timestamp"`
	}
	if err := json.Unmarshal(b, &raw); err != nil {
		return err
	}
	*d = messageData(raw.alias)
	switch v := raw.Timestamp.(type) {
	case float64:
		d.Timestamp = int64(v)
	case string:
		d.Timestamp, _ = strconv.ParseInt(v, 10, 64)
	}
	return nil
}
Defensive patterns

Strategy: type-guard

Validate before calling

var probe struct {
	Event string          `json:"event"`
	Data  json.RawMessage `json:"data"`
}
if err := json.Unmarshal(raw, &probe); err != nil {
	// skip frame before handling
}

Type guard

func validMessageFrame(data json.RawMessage) bool {
	var m map[string]any
	if json.Unmarshal(data, &m) != nil {
		return false
	}
	_, ok := m["content"].(string)
	return ok
}

Try / catch

if err := json.Unmarshal(frame.Data, &data); err != nil {
	slog.Warn("wps-agentspace: skipping malformed message frame", "error", err)
	return nil // log and continue, don't kill the loop
}

Prevention

When it happens

Trigger: event="message" whose frame.data is malformed JSON or whose field types differ from messageData (e.g. content as an object instead of string, timestamp as string instead of int64) — usually after a server-side API schema change or version mismatch.

Common situations: WPS AgentSpace rolling out a new message format that an older cc-connect build does not know; a corrupt/proxied frame; testing against a mock or newer dev endpoint emitting different messageData shapes.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/e7617bef37b38113. Report an issue: GitHub.