siyuan-note/siyuan · error
unsupported embedded request field
Error message
unsupported embedded request field: %s
What it means
decodeRequestFields walks the request struct's fields; anonymous (embedded) fields with no JSON name must be structs so they can be recursed into. An embedded non-struct (e.g. an embedded string, int, or interface) cannot be flattened, so this error names the offending field. It indicates an unsupported contract shape.
Solutions
- Give the embedded field an explicit json name instead of embedding it
- Change the embedded type to a struct, or wrap the primitive in a named field
- Restructure the request contract so all anonymous fields are structs
Example fix
// before
type Req struct {
Base
string // anonymous non-struct embed
}
// after
type Req struct {
Base
Note string `json:"note"`
} Defensive patterns
Strategy: validation
Validate before calling
func validateContractShape(v reflect.Value) error { t := v.Type(); for i := 0; i < t.NumField(); i++ { f := t.Field(i); if f.Anonymous && strings.Split(f.Tag.Get("json"), ",")[0] == "" && f.Type.Kind() != reflect.Struct { return fmt.Errorf("embedded field %s must be a struct", f.Name) } }; return nil } Type guard
func embeddable(f reflect.StructField) bool { return !f.Anonymous || strings.Split(f.Tag.Get("json"), ",")[0] != "" || f.Type.Kind() == reflect.Struct } Try / catch
if err := decodeRequestFields(value, fields); err != nil { if strings.HasPrefix(err.Error(), "unsupported embedded request field") { return fmt.Errorf("fix contract struct shape: %w", err) }; return err } Prevention
- Only embed structs anonymously in request contracts
- Give non-struct helper fields explicit json names
- Lint contract structs at build time for anonymous non-struct fields
When it happens
Trigger: Embedding a non-struct type (embedded string, embedded interface, embedded map) in a request contract struct without a json tag name.
Common situations: Embedding a type alias like `type ID string` directly; embedding time.Duration or another named primitive; auto-generating contracts from types with primitive embeds.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- unsupported enum field
- request contract must be a struct
- attribute view embedded base is missing
- catalog has no providers with API endpoints and valid models
- createDocTree document contains unknown field
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/5438178f1854f1a8.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/apicontract/decode.go:59
}
value := reflect.ValueOf(&request).Elem()
if value.Kind() != reflect.Struct {
return request, fmt.Errorf("request contract must be a struct")
}
err = decodeRequestFields(value, fields)
return request, err
}
func decodeRequestFields(value reflect.Value, fields map[string]json.RawMessage) error {
for i := 0; i < value.NumField(); i++ {
field := value.Type().Field(i)
name := strings.Split(field.Tag.Get("json"), ",")[0]
if (!field.IsExported() && !field.Anonymous) || name == "-" {
continue
}
if field.Anonymous && name == "" {
if field.Type.Kind() != reflect.Struct {
return fmt.Errorf("unsupported embedded request field: %s", field.Name)
}
if err := decodeRequestFields(value.Field(i), fields); err != nil {
return err
}
continue
}
options := "," + field.Tag.Get("api") + ","
has := func(option string) bool { return strings.Contains(options, ","+option+",") }
raw, present := fields[name]
if !present {
if has("optional") {
continue
}
return fmt.Errorf("Field [%s] is required", name)
}
isNull := bytes.Equal(bytes.TrimSpace(raw), []byte("null"))
if isNull && !has("nullable") && field.Type.Kind() != reflect.Pointer && !has("filterstrings") {
return fmt.Errorf("Field [%s] must not be null", name)View on GitHub (pinned to 9f775e8a12)