siyuan-note/siyuan · error

Field [removeKeys]: each element should be a non-empty…

Error message

Field [removeKeys]: each element should be a non-empty String

What it means

This error is returned when decoding the request for POST /api/storage/setViewState. It is produced when the generic decoder rejects the `removeKeys` field and the wrapper rewrites the message. It means `removeKeys` was not an array whose every element is a non-empty string (e.g. an object, a scalar, or an array containing numbers, nulls, or empty strings).

Solutions

  1. Pass removeKeys as an array of non-empty strings: {"key":"local","removeKeys":["k1","k2"]}
  2. Filter out empty or non-string entries before sending
  3. Omit removeKeys entirely if you have nothing to remove

Example fix

// before
{"key":"local", "removeKeys":{"k1":true}}
// after
{"key":"local", "removeKeys":["k1"]}
Defensive patterns

Strategy: validation

Validate before calling

const ok = Array.isArray(p.removeKeys) && p.removeKeys.every(k => typeof k === 'string' && k.length > 0);

Type guard

const isNonEmptyStringArray = (v) => Array.isArray(v) && v.every(k => typeof k === 'string' && k.length > 0);

Try / catch

try { const res = await fetchPost('/api/storage/setViewState', payload); if (res.code !== 0) throw new Error(res.msg); } catch (e) { console.error(e.message); }

Prevention

When it happens

Trigger: Calling /api/storage/setViewState with removeKeys like {"removeKeys":"a"}, {"removeKeys":[1,2]}, {"removeKeys":[""]}, or {"removeKeys":[null]}.

Common situations: A client passing an object map of keys-to-delete instead of an array; a script building removeKeys from a Set and including an empty entry; sending JSON after a variable was left undefined and serialized oddly.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

Thrown at kernel/apicontract/storage.go:41

			return request, errors.New("Field [rootIDs] should be of type [Array]")
		}
		for _, entry := range entries {
			var id string
			if json.Unmarshal(entry, &id) == nil && id != "" {
				request.RootIDs = append(request.RootIDs, id)
			}
		}
		return
	}
	plain := PatchViewState
	PatchViewState.decodeRequest = func(reader io.Reader) (ViewStatePatchRequest, error) {
		request, err := plain.Decode(reader)
		if err != nil {
			switch {
			case strings.HasPrefix(err.Error(), "Field [values]"):
				err = errors.New("Field [values]: should be of type [Object]")
			case strings.HasPrefix(err.Error(), "Field [removeKeys]"):
				err = errors.New("Field [removeKeys]: each element should be a non-empty String")
			}
		}
		return request, err
	}
}

type RecentDocUpdateRequest struct {
	RootID string `json:"rootID" api:"optional,nullable"`
}
type RecentDocsUpdateRequest struct {
	RootIDs []string `json:"rootIDs" api:"optional,nullable"`
}

type StorageKeyRequest struct {
	Key string `json:"key" api:"trim"`
}
type StorageKeysRequest struct {
	Keys []string `json:"keys"`

View on GitHub (pinned to 9f775e8a12)