{"record":{"id":"76bcf085fec60192","repo":"siyuan-note/siyuan","slug":"field-type-must-not-be-empty","errorCode":null,"errorMessage":"Field [type] must not be empty","messagePattern":"Field \\[type\\] must not be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/apicontract/graph_input.go","lineNumber":56,"sourceCode":"}\n\ntype SetGraphConfRequest struct {\n\tType string             `json:\"type\" api:\"trim\"`\n\tConf GraphConfiguration `json:\"conf\"`\n}\n\nfunc init() {\n\tSetGraphConf.decodeRequest = func(reader io.Reader) (request SetGraphConfRequest, err error) {\n\t\tfields, err := blockRequestFields(reader, \"/api/graph/setGraphConf\")\n\t\tif err != nil {\n\t\t\treturn request, err\n\t\t}\n\t\tif request.Type, err = legacyField[string](fields, \"type\", \"String\", true); err != nil {\n\t\t\treturn request, err\n\t\t}\n\t\trequest.Type = strings.TrimSpace(request.Type)\n\t\tif request.Type == \"\" {\n\t\t\treturn request, fmt.Errorf(\"Field [type] must not be empty\")\n\t\t}\n\t\tif len(fields[\"conf\"]) == 0 {\n\t\t\treturn request, fmt.Errorf(\"Field [conf] is required\")\n\t\t}\n\t\terr = json.Unmarshal(fields[\"conf\"], &request.Conf)\n\t\treturn\n\t}\n}\n\ntype GraphConfigurationData struct {\n\tglobal *GlobalGraphConf\n\tlocal  *LocalGraphConf\n}\n\nfunc GlobalGraphConfiguration(value GlobalGraphConf) GraphConfigurationData {\n\treturn GraphConfigurationData{global: &value}\n}\nfunc LocalGraphConfiguration(value LocalGraphConf) GraphConfigurationData {","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/apicontract/graph_input.go#L38-L74","documentation":"The graph request decoder requires a `type` field of type String that is non-empty after trimming whitespace. legacyField first enforces presence/type, then the code trims the value and rejects an all-whitespace string. This ensures every graph request names its configuration type explicitly.","triggerScenarios":"Calling the graph set-configuration endpoint with `{}` (missing `type`), with `\"type\": \"\"`, or with `\"type\": \"   \"`. Missing type actually surfaces as 'Field [type] is required' from legacyField; this message appears when type is present but empty/whitespace.","commonSituations":"Frontend code building the payload dynamically and leaving the type variable unset or empty; API consumers omitting required fields after copying an example.","solutions":["Include a non-empty \"type\" field in the request, e.g. {\"type\": \"graph\"}","Trim or default the type value in client code before sending","Check that the field key is exactly \"type\" (case-sensitive)"],"exampleFix":"// before\n{\"type\": \"\", \"conf\": {}}\n// after\n{\"type\": \"graph\", \"conf\": {}}","handlingStrategy":"validation","validationCode":"if (typeof body.type !== \"string\" || body.type.trim() === \"\") {\n  throw new Error(\"type must be a non-empty string\");\n}","typeGuard":"const hasNonEmptyString = (o, k) => typeof o[k] === \"string\" && o[k].trim().length > 0;","tryCatchPattern":null,"preventionTips":["Validate payloads before sending","Trim user-supplied values before assigning them to type","Never send whitespace-only strings for required identifiers"],"tags":["api","validation","empty-value","input"],"backgroundTag":"empty-required-field","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}