siyuan-note/siyuan · error

Field [scope] should be of type [String]

Error message

Field [scope] should be of type [String]

What it means

The checkBlockRef endpoint's scope field, when present, must be a JSON string (or absent, in which case it defaults to "blocks"). Explicit JSON null also counts as a type error. This guards the scope selector that steers which reference kinds are checked.

Solutions

  1. Send scope as a quoted string, e.g. {"scope":"blocks"} or the supported child-document scope value.
  2. Omit the scope key entirely to get the "blocks" default.
  3. Replace null with key omission on the client before serializing.
  4. If the value comes from a select input, ensure it yields a single string, not an array or number.

Example fix

// before
{"ids": ["20240101120000-abcdefg"], "scope": null}
// after
{"ids": ["20240101120000-abcdefg"]} // scope omitted, defaults to "blocks"
Defensive patterns

Strategy: type-guard

Validate before calling

if ("scope" in payload && (payload.scope === null || typeof payload.scope !== "string")) { delete payload.scope; }

Type guard

const isScope = (v) => typeof v === "string" && v.length > 0;

Try / catch

try {
  await post("/api/block/checkBlockRef", payload);
} catch (e) {
  if (String(e.message).includes("Field [scope] should be of type [String]")) {
    delete payload.scope; // fall back to the "blocks" default
    await post("/api/block/checkBlockRef", payload);
  } else { throw e; }
}

Prevention

When it happens

Trigger: POSTing to /api/block/checkBlockRef with {"scope":123}, {"scope":null}, {"scope":["blocks"]}, or any non-string value for scope.

Common situations: Clients sending null to mean 'unset' (omit the key instead), arrays built from multi-select UIs, or numeric enum constants from another API mapped onto scope.

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/201a426bd01a342d. Report an issue: GitHub.

Appendix: source

Thrown at kernel/apicontract/block_remaining.go:73

func blockRequestFields(reader io.Reader, path string) (fields map[string]json.RawMessage, err error) {
	err = json.NewDecoder(reader).Decode(&fields)
	if err != nil {
		if errors.Is(err, io.EOF) {
			err = errors.New("the request body is empty or truncated (EOF)")
		}
		err = fmt.Errorf("Parses request [%s] failed: %s", path, err)
	}
	return
}

func decodeCheckBlockRef(reader io.Reader) (request CheckBlockRefRequest, err error) {
	fields, err := blockRequestFields(reader, "/api/block/checkBlockRef")
	if err != nil {
		return request, err
	}
	if raw, present := fields["scope"]; present {
		if bytes.Equal(raw, []byte("null")) || json.Unmarshal(raw, &request.Scope) != nil {
			return request, errors.New("Field [scope] should be of type [String]")
		}
	}
	if strings.TrimSpace(request.Scope) == "" {
		request.Scope = "blocks"
	}
	readArray := func(key string, required, nonempty bool) ([]string, error) {
		raw, present := fields[key]
		if !present && !required {
			return nil, nil
		}
		if !present || bytes.Equal(raw, []byte("null")) {
			return nil, fmt.Errorf("Field [%s] is required", key)
		}
		var entries []json.RawMessage
		if json.Unmarshal(raw, &entries) != nil {
			return nil, fmt.Errorf("Field [%s] should be of type [Array]", key)
		}
		if nonempty && len(entries) == 0 {

View on GitHub (pinned to 9f775e8a12)