Tencent/WeKnora · error

flexibleStatus: expected string or integer, got %s: %w

Error message

flexibleStatus: expected string or integer, got %s: %w

What it means

flexibleStatus is a custom JSON unmarshaler that accepts Yuque status fields as either a string or an integer (Yuque has changed this shape historically). When the JSON value is neither, it decodes as int64 and reports the raw bytes plus the underlying unmarshal error. This exists so silent coercion of booleans/floats/objects into status strings cannot happen.

Source

Thrown at internal/datasource/connector/yuque/types.go:115

	if string(b) == "null" {
		*s = ""
		return nil
	}
	if len(b) > 0 && b[0] == '"' {
		var str string
		if err := json.Unmarshal(b, &str); err != nil {
			return err
		}
		*s = flexibleStatus(str)
		return nil
	}
	// Integer form. We decode to int64 so that floats, booleans, arrays, and
	// objects fail loudly instead of being silently stringified — if Yuque
	// changes the shape again, we'd rather surface a clear error than feed
	// garbage to the Status == "1" comparison.
	var i int64
	if err := json.Unmarshal(b, &i); err != nil {
		return fmt.Errorf("flexibleStatus: expected string or integer, got %s: %w", b, err)
	}
	*s = flexibleStatus(strconv.FormatInt(i, 10))
	return nil
}

// apiErrorBody is the error body shape Yuque sometimes returns on non-2xx.
type apiErrorBody struct {
	Message string `json:"message"`
	Status  int    `json:"status"`
}

// v2UserResponse wraps GET /api/v2/user.
type v2UserResponse struct {
	Data v2User `json:"data"`
}

type v2User struct {
	ID    int64  `json:"id"`

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Inspect the 'got %s' portion of the message to see the actual JSON bytes returned and confirm the new shape.
  2. Update flexibleStatus (or the fixture) to support the new shape if Yuque changed their API, adding an explicit case for it.
  3. Fix mocked/fixture data to return status as a string (e.g. "1") or integer (e.g. 1).

Example fix

// before (fixture)
{"status": true}
// after
{"status": "1"}
Defensive patterns

Strategy: validation

Validate before calling

switch v := raw.(type) {
case string, int, int64, float64:
    // acceptable status forms
default:
    return fmt.Errorf("status must be string or integer, got %T", raw)
}

Type guard

func isStringOrNumber(b []byte) bool {
    var v any
    if json.Unmarshal(b, &v) != nil { return false }
    switch v.(type) { case string, float64: return true; default: return false }
}

Try / catch

if err := json.Unmarshal(body, &resp); err != nil {
    if strings.Contains(err.Error(), "flexibleStatus") {
        log.Printf("Yuque status shape changed; raw=%s", body)
    }
    return err
}

Prevention

When it happens

Trigger: json.Unmarshal into a struct containing a flexibleStatus field where the API returned a boolean, float, array, or object for the status field.

Common situations: A Yuque API version change altering the status field shape; mocking the API with a wrong type (e.g. status: true); proxy fixtures returning different serialization.

Related errors


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/d775ed21827121c6. Report an issue: GitHub.