siyuan-note/siyuan · error
Field [ ] has an invalid constant
Error message
Field [%s] has an invalid constant
What it means
This error comes from the SiYuan kernel's strict request decoder in kernel/apicontract/decode.go (decodeRequestFields). When a contract field is declared with a fixed constant (a pinned value), the decoder unmarshals the submitted value and compares it with the declared constant using reflect.DeepEqual; any difference means the client sent a value that violates the API contract. It protects endpoints whose fields must equal a specific constant and cannot be freely chosen by the caller.
Solutions
- Read the endpoint's contract definition in kernel/apicontract/ and set the field exactly to the declared constant value
- Remove the field from your payload if the contract marks it as a constant that the server injects itself
- Update your client/plugin code to match the current SiYuan API version's contract
- If you believe the constant is wrong, file an issue instead of bypassing the check
Example fix
// before
fetchPost("/api/filetree/copyDoc", {path: p, title: t, "notebook": "wrong-id-constant"})
// after
fetchPost("/api/filetree/copyDoc", {path: p, title: t, notebook: NOTEBOOK_ID_CONSTANT}) Defensive patterns
Strategy: validation
Validate before calling
function assertConstants(payload, constants) {
for (const [name, expected] of Object.entries(constants)) {
if (JSON.stringify(payload[name]) !== JSON.stringify(expected)) {
throw new Error(`Field [${name}] must equal ${JSON.stringify(expected)}`);
}
}
}
assertConstants(payload, { notebook: NOTEBOOK_ID_CONSTANT }); Type guard
const isConstantMatch = (v, c) => JSON.stringify(v) === JSON.stringify(c);
Prevention
- Copy contract constants from the apicontract source rather than retyping them
- Pin your client to a SiYuan version and re-check constants on upgrades
- Keep payload builders in one module so constant fields are set in one place
- Never hand-edit constant fields in saved request templates
When it happens
Trigger: Calling a kernel API whose contract pins a field to a constant (via contract field metadata) and sending any other value for that field; e.g. passing a different string, number, or object to a field declared as a constant in kernel/apicontract/ definitions decoded by Decode/decodeRequestFields/avDecodeBoundFields/fileTreeBind.
Common situations: Hand-crafted fetch/curl requests built from outdated API docs; plugins hard-coding payloads copied from an older SiYuan version after the contract changed; copy-pasted request bodies where one field was edited but a constant field was accidentally changed too.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/ee3f70e7c33d7458.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/apicontract/decode.go:152
}
if !found {
return fmt.Errorf("Field [%s] has an invalid value", name)
}
}
if strings.HasPrefix(option, "const=") {
var expected, actual any
if err := json.Unmarshal([]byte(strings.TrimPrefix(option, "const=")), &expected); err != nil {
return err
}
data, err := json.Marshal(value.Field(i).Interface())
if err != nil {
return err
}
if err := json.Unmarshal(data, &actual); err != nil {
return err
}
if !reflect.DeepEqual(expected, actual) {
return fmt.Errorf("Field [%s] has an invalid constant", name)
}
}
}
}
return nil
}
// decodeRequestValue 递归绑定复合参数,避免数组元素和嵌套字段绕过空值及必填检查。
func decodeRequestValue(raw json.RawMessage, value reflect.Value) error {
if value.Type() == reflect.TypeFor[JSONValue]() || value.Type() == reflect.TypeFor[PublishDataValue]() {
return json.Unmarshal(raw, value.Addr().Interface())
}
if bytes.Equal(bytes.TrimSpace(raw), []byte("null")) {
switch value.Kind() {
case reflect.Pointer, reflect.Map, reflect.Slice:
value.SetZero()
return nil
default:View on GitHub (pinned to 9f775e8a12)