siyuan-note/siyuan · error
Field [id] must not be empty
Error message
Field [id] must not be empty
What it means
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.
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
Example fix
// before
fetchPost("/api/filetree/removeDoc", { id: docId || "" });
// after
if (!docId?.trim()) return;
fetchPost("/api/filetree/removeDoc", { id: docId.trim() }); Defensive patterns
Strategy: validation
Validate before calling
const trimmed = String(id ?? "").trim();
if (!trimmed) throw new Error("cannot call removeDoc without a document id"); Type guard
const hasId = (b) => typeof b.id === "string" && b.id.trim() !== "";
Try / catch
try {
await fetchPost("/api/filetree/removeDoc", { id });
} catch (e) {
if (String(e.message).includes("[id] must not be empty")) {
// re-resolve the current document id before retrying
}
} Prevention
- 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
When it happens
Trigger: POST /api/filetree/removeDoc with {"id":""} or {"id":" "}.
Common situations: 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.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- Conf.Language(126) (localized empty-bookmark-name message)
- createDocTree document
- createDocTree document title must not be empty
- database field name and type are required
- Field [id] must not be empty
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/cb75290e0ac3b279.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/apicontract/filetree_input.go:169
fileTreeJSONDecoder(&CreateDocWithMd)
fileTreeJSONDecoder(&GetDocCreateSavePath)
fileTreeJSONDecoder(&GetRefCreateSavePath)
fileTreeJSONDecoder(&GetShorthandSavePath)
fileTreeJSONDecoder(&ChangeSort)
fileTreeJSONDecoder(&SearchDocs)
fileTreeJSONDecoder(&GetPublishAccess)
fileTreeJSONDecoder(&AuthFilePublishAccess)
trimIDDecoder := func(path string) func(io.Reader) (FileTreeTrimIDRequest, error) {
return func(reader io.Reader) (r FileTreeTrimIDRequest, err error) {
fields, err := fileTreeRequestFields(reader, path)
if err != nil {
return r, err
}
r.ID, err = legacyField[string](fields, "id", "String", true)
if err == nil {
r.ID = strings.TrimSpace(r.ID)
if r.ID == "" {
err = fmt.Errorf("Field [id] must not be empty")
}
}
return r, err
}
}
RemoveDocByID.decodeRequest = trimIDDecoder(RemoveDocByID.definition.Path)
GetPathByID.decodeRequest = trimIDDecoder(GetPathByID.definition.Path)
GetIDsByHPath.decodeRequest = func(reader io.Reader) (r FileTreeOptionalPathRequest, err error) {
fields, err := fileTreeRequestFields(reader, GetIDsByHPath.definition.Path)
if err != nil {
return r, err
}
for _, key := range []string{"path", "notebook"} {
if len(fields[key]) == 0 || bytes.Equal(fields[key], []byte("null")) {
return r, nil
}
}
return fileTreeBind[FileTreeOptionalPathRequest](fields)View on GitHub (pinned to 9f775e8a12)