siyuan-note/siyuan · error
Field [ ] must not be null
Error message
Field [%s] must not be null
What it means
In avDecodeBoundFields, a bound field present in the request but explicitly JSON null is rejected with 'Field [<name>] must not be null'. Bound fields carry structural payloads (e.g. filters data, attr values) that the decoder must normalize, and null would break the placeholder-based decoding.
Solutions
- Send an empty container instead of null: [] for array fields (data/values/blocksValues), {} for object fields (value/group)
- Coerce null to the empty default in the client before the request
- Omit nothing else — the field must exist with a real value
Example fix
// before
fetchPost("/api/av/setAttrViewSorts", {avID, data: null});
// after
fetchPost("/api/av/setAttrViewSorts", {avID, data: sorts ?? []}); Defensive patterns
Strategy: validation
Validate before calling
function deNull(obj) { for (const k of ["data","value","values","blocksValues","group"]) if (obj[k] === null) obj[k] = Array.isArray(obj[k]) || ["data","values","blocksValues"].includes(k) ? [] : {}; return obj; } Type guard
const isNotNull = (v) => v !== null && v !== undefined;
Try / catch
try { await post(avEndpoint, payload); } catch (e) { if (/must not be null/.test(e.message)) { payload = withDefaults(payload); /* retry once */ } else throw e; } Prevention
- Never serialize undefined attributes of request objects; set explicit defaults
- Configure JSON serializers to omit null or map null to empty containers
- Coerce null to [] / {} at the payload-construction site
When it happens
Trigger: Sending JSON null for a bound field: {"avID":"...","data":null} to /api/av/setAttrViewFilters or setAttrViewSorts, {"value":null} to setAttributeViewBlockAttr, {"values":null} to batchSetAttributeViewBlockAttrs, {"blocksValues":null}, {"group":null}.
Common situations: Clients initializing fields to null as a default, JSON serializers emitting null for undefined values, migrations from older API versions where null was tolerated.
Related errors
- Field [keyIDs] must not be null
- AI editor action must not be empty
- block [ ] type is locked: expected , got
- block swap requires two non-document blocks
- Bookmark cannot be empty
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/c67a0f1642a2333a.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/apicontract/av_decode.go:25
"io"
"reflect"
"strings"
)
// avDecodeBoundFields 仅对原本经过 JSON 结构体绑定的字段保留大小写匹配和数字归一化。
func avDecodeBoundFields[Request any](reader io.Reader, path string, boundFields map[string]string, ignoredBools []string) (request Request, err error) {
fields, err := blockRequestFields(reader, path)
if err != nil {
return request, err
}
original := map[string]json.RawMessage{}
for name, placeholder := range boundFields {
raw, present := fields[name]
if !present {
return request, fmt.Errorf("Field [%s] is required", name)
}
if bytes.Equal(bytes.TrimSpace(raw), []byte("null")) {
return request, fmt.Errorf("Field [%s] must not be null", name)
}
original[name] = raw
fields[name] = json.RawMessage(placeholder)
}
for _, name := range ignoredBools {
original[name] = fields[name]
delete(fields, name)
}
value := reflect.ValueOf(&request).Elem()
if err = decodeRequestFields(value, fields); err != nil {
return request, err
}
for i := 0; i < value.NumField(); i++ {
field := value.Type().Field(i)
name := field.Tag.Get("json")
raw, present := original[name]
if !present {
continueView on GitHub (pinned to 9f775e8a12)