siyuan-note/siyuan · error

each key requires name and type

Error message

each key requires name and type

What it means

databaseCreateKeySpecs requires every key object to carry a non-blank 'name' and a non-blank 'type' (after trimming whitespace). If either is missing or empty, the tool returns 'each key requires name and type'. These map to the attribute-view key definitions used to build the new database.

Source

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

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 8641553a1f)

Solutions

  1. Add both name and type to every key object; valid types include text, number, date, select, mSelect, block, url, email, phone, etc.
  2. Trim your inputs and ensure neither field is whitespace-only.
  3. Check for JSON typos such as "Name" vs the lowercase "name" key the parser expects.
  4. Validate key specs client-side before calling databaseCreate.

Example fix

// before
{ "keys": [ { "name": "Due" } ] }
// after
{ "keys": [ { "name": "Due", "type": "date" } ] }
Defensive patterns

Strategy: validation

Validate before calling

function assertKeyRequiredFields(keys) {
  for (const k of keys) {
    const name = (k.name ?? '').trim();
    const type = (k.type ?? '').trim();
    if (!name || !type) {
      throw new TypeError(`key ${JSON.stringify(k)} requires non-empty name and type`);
    }
  }
}

Type guard

function isCompleteKeySpec(k) { return typeof k.name === 'string' && k.name.trim() !== '' && typeof k.type === 'string' && k.type.trim() !== ''; }

Try / catch

try {
  await mcp.call("databaseCreate", { name, keys });
} catch (e) {
  if (e.message === "each key requires name and type") {
    // find the key missing name/type and complete it
  }
}

Prevention

When it happens

Trigger: Calling databaseCreate with a key entry like {"name":"Notes"} (no type), {"type":"text"} (no name), or {"name":" ","type":"text"} (whitespace-only).

Common situations: Agents omitting the type when it seems obvious; clients copying specs from an existing database but dropping fields; trailing-space names from copy-paste that then fail after TrimSpace.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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