siyuan-note/siyuan · error

each key requires name and type

Error message

each key requires name and type

What it means

databaseCreateKeySpecs (kernel/mcp/tools/database.go) requires every key object to carry a non-empty (after trimming) `name` and `type`; a missing or blank one is rejected with this error. Icon is optional and defaults to empty.

Solutions

  1. Ensure every key object has non-empty name and type strings
  2. Check for misspelled property names in the key object (name/type vs label/kind)
  3. Trim whitespace in names/types client-side and reject blanks before the call
  4. Use one of the supported key types (text, number, date, select, mSelect, etc.)

Example fix

// before
keys: [{type: "text"}]
// after
keys: [{name: "Title", type: "text"}]
Defensive patterns

Strategy: validation

Validate before calling

const ok = keys.every(k => typeof k?.name === "string" && k.name.trim() && typeof k?.type === "string" && k.type.trim());

Type guard

const hasNameAndType = (k) => !!(k?.name?.trim() && k?.type?.trim());

Prevention

When it happens

Trigger: Keys like [{"name":"","type":"text"}], [{"type":"text"}], or [{"name":" ","type":" "}] passed to the database create MCP tool; type strings not matching a supported attribute-view key type will pass this check but fail later.

Common situations: Programmatic key generation leaving name empty when the header cell is blank; typos in the field name (e.g. "label" instead of "name"); LLM-generated specs omitting type.

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


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

Appendix: source

Thrown at kernel/mcp/tools/database.go:217

func databaseCreateKeySpecs(value any) (ret []*model.AttributeViewCreateKey, err error) {
	if nil == value {
		return []*model.AttributeViewCreateKey{}, nil
	}
	items, ok := value.([]any)
	if !ok {
		return nil, errors.New("keys must be an array")
	}
	for _, item := range items {
		data, itemOK := item.(map[string]any)
		if !itemOK {
			return nil, errors.New("each key must be an object")
		}
		name, _ := data["name"].(string)
		keyType, _ := data["type"].(string)
		icon, _ := data["icon"].(string)
		if "" == strings.TrimSpace(name) || "" == strings.TrimSpace(keyType) {
			return nil, errors.New("each key requires name and type")
		}
		ret = append(ret, &model.AttributeViewCreateKey{Name: name, Type: keyType, Icon: icon})
	}
	return
}

func databaseSuccess(action string, data any) (CallToolResult, error) {
	output := &databaseToolOutput{Action: action, Data: data}
	serialized, err := json.Marshal(output)
	if nil != err {
		return CallToolResult{}, err
	}
	return CallToolResult{
		Content:              []ContentItem{{Type: "text", Text: string(serialized)}},
		StructuredContent:    output,
		StructuredContentSet: true,
	}, nil
}

View on GitHub (pinned to 9f775e8a12)