siyuan-note/siyuan · error

Field [sortMode] must be an integer or null

Error message

Field [sortMode] must be an integer or null: %s

What it means

Once present, the raw 'sortMode' value must unmarshal into a Go int or be JSON null. Anything else (string "7", bool, object, float with fraction) fails json.Unmarshal into int and produces this message with the underlying decoder error appended. The library is strict because sortMode maps directly to an enum-like integer in the kernel config.

Solutions

  1. Convert the value to an integer before sending, e.g. parseInt(mode, 10)
  2. Send null explicitly if clearing the mode is intended
  3. Consult the API docs for the valid integer sort-mode codes

Example fix

// before
fetchPost("/api/filetree/setDocSortMode", { id, sortMode: String(mode) });
// after
fetchPost("/api/filetree/setDocSortMode", { id, sortMode: Number.parseInt(mode, 10) });
Defensive patterns

Strategy: type-guard

Validate before calling

if (!Number.isInteger(sortMode)) throw new TypeError(`sortMode must be an integer, got ${typeof sortMode}`);

Type guard

const isSortMode = (v) => v === null || Number.isInteger(v);

Try / catch

try {
  await fetchPost("/api/filetree/setDocSortMode", { id, sortMode });
} catch (e) {
  if (String(e.message).includes("must be an integer or null")) {
    await fetchPost("/api/filetree/setDocSortMode", { id, sortMode: parseInt(sortMode, 10) });
  }
}

Prevention

When it happens

Trigger: POST /api/filetree/setDocSortMode with {"id":"...","sortMode":"7"} or sortMode: 1.5 or sortMode: {"mode":7}.

Common situations: JavaScript clients that keep the mode as a numeric string from a select element; JSON produced by template interpolation without type conversion; API consumers guessing the field is a string code like "name".

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/06b7baa96c52ba65. Report an issue: GitHub.

Appendix: source

Thrown at kernel/apicontract/filetree_input.go:130

		delete(fields, "querySubTypes")
		if value, ok := filtered["subTypes"]; ok {
			fields["querySubTypes"] = value
		}
	}
	return fileTreeBind[FileTreeGetDocOptions](fields)
}

func (r FileTreeSortModeRequest) Mode() (*int, error) {
	raw := r.sortModeFields["sortMode"]
	if len(raw) == 0 {
		return nil, fmt.Errorf("Field [sortMode] is required")
	}
	if bytes.Equal(bytes.TrimSpace(raw), []byte("null")) {
		return nil, nil
	}
	var value int
	if err := json.Unmarshal(raw, &value); err != nil {
		return nil, fmt.Errorf("Field [sortMode] must be an integer or null: %s", err)
	}
	return &value, nil
}

func init() {
	fileTreeJSONDecoder(&MoveLocalShorthands)
	fileTreeJSONDecoder(&UpsertIndexes)
	fileTreeJSONDecoder(&RemoveIndexes)
	fileTreeJSONDecoder(&Doc2Heading)
	fileTreeJSONDecoder(&GetHPathByPath)
	fileTreeJSONDecoder(&GetHPathsByPaths)
	fileTreeJSONDecoder(&GetHPathByID)
	fileTreeJSONDecoder(&GetFullHPathByID)
	fileTreeJSONDecoder(&MoveDocs)
	fileTreeJSONDecoder(&MoveDocsByID)
	fileTreeJSONDecoder(&RemoveDoc)
	fileTreeJSONDecoder(&RemoveDocs)
	fileTreeJSONDecoder(&RenameDoc)

View on GitHub (pinned to 9f775e8a12)