{"record":{"id":"d8feaa3ecf5f45af","repo":"siyuan-note/siyuan","slug":"each-key-requires-name-and-type","errorCode":null,"errorMessage":"each key requires name and type","messagePattern":"each key requires name and type","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/mcp/tools/database.go","lineNumber":209,"sourceCode":"\nfunc databaseCreateKeySpecs(value any) (ret []*model.AttributeViewCreateKey, err error) {\n\tif nil == value {\n\t\treturn []*model.AttributeViewCreateKey{}, nil\n\t}\n\titems, ok := value.([]any)\n\tif !ok {\n\t\treturn nil, errors.New(\"keys must be an array\")\n\t}\n\tfor _, item := range items {\n\t\tdata, itemOK := item.(map[string]any)\n\t\tif !itemOK {\n\t\t\treturn nil, errors.New(\"each key must be an object\")\n\t\t}\n\t\tname, _ := data[\"name\"].(string)\n\t\tkeyType, _ := data[\"type\"].(string)\n\t\ticon, _ := data[\"icon\"].(string)\n\t\tif \"\" == strings.TrimSpace(name) || \"\" == strings.TrimSpace(keyType) {\n\t\t\treturn nil, errors.New(\"each key requires name and type\")\n\t\t}\n\t\tret = append(ret, &model.AttributeViewCreateKey{Name: name, Type: keyType, Icon: icon})\n\t}\n\treturn\n}\n\nfunc databaseSuccess(action string, data any) (CallToolResult, error) {\n\toutput := &databaseToolOutput{Action: action, Data: data}\n\tserialized, err := json.Marshal(output)\n\tif nil != err {\n\t\treturn CallToolResult{}, err\n\t}\n\treturn CallToolResult{\n\t\tContent:              []ContentItem{{Type: \"text\", Text: string(serialized)}},\n\t\tStructuredContent:    output,\n\t\tStructuredContentSet: true,\n\t}, nil\n}","sourceCodeStart":191,"sourceCodeEnd":227,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/mcp/tools/database.go#L191-L227","documentation":"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.","triggerScenarios":"Calling databaseCreate with a key entry like {\"name\":\"Notes\"} (no type), {\"type\":\"text\"} (no name), or {\"name\":\"  \",\"type\":\"text\"} (whitespace-only).","commonSituations":"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.","solutions":["Add both name and type to every key object; valid types include text, number, date, select, mSelect, block, url, email, phone, etc.","Trim your inputs and ensure neither field is whitespace-only.","Check for JSON typos such as \"Name\" vs the lowercase \"name\" key the parser expects.","Validate key specs client-side before calling databaseCreate."],"exampleFix":"// before\n{ \"keys\": [ { \"name\": \"Due\" } ] }\n// after\n{ \"keys\": [ { \"name\": \"Due\", \"type\": \"date\" } ] }","handlingStrategy":"validation","validationCode":"function assertKeyRequiredFields(keys) {\n  for (const k of keys) {\n    const name = (k.name ?? '').trim();\n    const type = (k.type ?? '').trim();\n    if (!name || !type) {\n      throw new TypeError(`key ${JSON.stringify(k)} requires non-empty name and type`);\n    }\n  }\n}","typeGuard":"function isCompleteKeySpec(k) { return typeof k.name === 'string' && k.name.trim() !== '' && typeof k.type === 'string' && k.type.trim() !== ''; }","tryCatchPattern":"try {\n  await mcp.call(\"databaseCreate\", { name, keys });\n} catch (e) {\n  if (e.message === \"each key requires name and type\") {\n    // find the key missing name/type and complete it\n  }\n}","preventionTips":["Include both name and type on every key; trim whitespace before sending","Use lowercase argument keys exactly (name, type, icon) — no capitalized variants","Validate against the key-type enum in the client before calling"],"tags":["mcp","argument-validation","database"],"backgroundTag":"missing-required-argument","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}