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
- Inspect the 'got %s' portion of the message to see the actual JSON bytes returned and confirm the new shape.
- Update flexibleStatus (or the fixture) to support the new shape if Yuque changed their API, adding an explicit case for it.
- 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
- Pin/mock Yuque API responses with realistic status types (string "1" or int 1).
- Keep fixtures updated when the Yuque API version changes.
- Handle errors from UnmarshalJSON loudly rather than ignoring partial decode failures.
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
- args must be a string or an array of strings: %w
- logical operator %s requires an array of conditions
- failed to unmarshal condition at index %d: %w
- unmarshal page: %w
- unmarshal database: %w
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/d775ed21827121c6.
Report an issue: GitHub.