{"record":{"id":"cb75290e0ac3b279","repo":"siyuan-note/siyuan","slug":"field-id-must-not-be-empty","errorCode":null,"errorMessage":"Field [id] must not be empty","messagePattern":"Field \\[id\\] must not be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/apicontract/filetree_input.go","lineNumber":169,"sourceCode":"\tfileTreeJSONDecoder(&CreateDocWithMd)\n\tfileTreeJSONDecoder(&GetDocCreateSavePath)\n\tfileTreeJSONDecoder(&GetRefCreateSavePath)\n\tfileTreeJSONDecoder(&GetShorthandSavePath)\n\tfileTreeJSONDecoder(&ChangeSort)\n\tfileTreeJSONDecoder(&SearchDocs)\n\tfileTreeJSONDecoder(&GetPublishAccess)\n\tfileTreeJSONDecoder(&AuthFilePublishAccess)\n\ttrimIDDecoder := func(path string) func(io.Reader) (FileTreeTrimIDRequest, error) {\n\t\treturn func(reader io.Reader) (r FileTreeTrimIDRequest, err error) {\n\t\t\tfields, err := fileTreeRequestFields(reader, path)\n\t\t\tif err != nil {\n\t\t\t\treturn r, err\n\t\t\t}\n\t\t\tr.ID, err = legacyField[string](fields, \"id\", \"String\", true)\n\t\t\tif err == nil {\n\t\t\t\tr.ID = strings.TrimSpace(r.ID)\n\t\t\t\tif r.ID == \"\" {\n\t\t\t\t\terr = fmt.Errorf(\"Field [id] must not be empty\")\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn r, err\n\t\t}\n\t}\n\tRemoveDocByID.decodeRequest = trimIDDecoder(RemoveDocByID.definition.Path)\n\tGetPathByID.decodeRequest = trimIDDecoder(GetPathByID.definition.Path)\n\tGetIDsByHPath.decodeRequest = func(reader io.Reader) (r FileTreeOptionalPathRequest, err error) {\n\t\tfields, err := fileTreeRequestFields(reader, GetIDsByHPath.definition.Path)\n\t\tif err != nil {\n\t\t\treturn r, err\n\t\t}\n\t\tfor _, key := range []string{\"path\", \"notebook\"} {\n\t\t\tif len(fields[key]) == 0 || bytes.Equal(fields[key], []byte(\"null\")) {\n\t\t\t\treturn r, nil\n\t\t\t}\n\t\t}\n\t\treturn fileTreeBind[FileTreeOptionalPathRequest](fields)","sourceCodeStart":151,"sourceCodeEnd":187,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/apicontract/filetree_input.go#L151-L187","documentation":"The removeDoc contract decoder validates the 'id' field: it must be a non-empty string after trimming whitespace. An empty id cannot identify any document, so the request is rejected with 'Field [id] must not be empty' before reaching the filetree logic.","triggerScenarios":"POST /api/filetree/removeDoc with {\"id\":\"\"} or {\"id\":\"   \"}.","commonSituations":"A variable holding the block/document ID that was never assigned; UI code deleting before the doc finished loading (ID still empty); string trimming removing a whitespace-only ID that looked valid; stale frontend state after a doc was re-created.","solutions":["Ensure a valid document ID (e.g. 20240101120000-abcdefg) is loaded before calling the API","Add a client-side check that the ID is non-empty before invoking the endpoint","Re-query the document to refresh its ID if it may have changed","Skip the call entirely when no document is selected"],"exampleFix":"// before\nfetchPost(\"/api/filetree/removeDoc\", { id: docId || \"\" });\n// after\nif (!docId?.trim()) return;\nfetchPost(\"/api/filetree/removeDoc\", { id: docId.trim() });","handlingStrategy":"validation","validationCode":"const trimmed = String(id ?? \"\").trim();\nif (!trimmed) throw new Error(\"cannot call removeDoc without a document id\");","typeGuard":"const hasId = (b) => typeof b.id === \"string\" && b.id.trim() !== \"\";","tryCatchPattern":"try {\n  await fetchPost(\"/api/filetree/removeDoc\", { id });\n} catch (e) {\n  if (String(e.message).includes(\"[id] must not be empty\")) {\n    // re-resolve the current document id before retrying\n  }\n}","preventionTips":["Gate destructive calls on a loaded document","Check id presence in UI state before rendering delete actions","Re-fetch doc metadata after structural changes that can change ids"],"tags":["validation","required-field","empty-value"],"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"}