{"record":{"id":"f6fb67e2c15cb001","repo":"siyuan-note/siyuan","slug":"keyword-is-required","errorCode":null,"errorMessage":"keyword is required","messagePattern":"keyword is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/cli/cmd/document.go","lineNumber":354,"sourceCode":"\t\tif \"/\" == targetHPath {\n\t\t\treturn \"/\", nil\n\t\t}\n\t}\n\n\tif targetPath, found := lookup(targetHPath); found {\n\t\treturn targetPath, nil\n\t}\n\treturn \"\", fmt.Errorf(\"target human-readable path not found: %s\", targetHPath)\n}\n\nvar documentSearchCmd = &cobra.Command{\n\tUse:   \"search <keyword>\",\n\tShort: \"Search documents by keyword\",\n\tArgs:  cobra.MinimumNArgs(1),\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tkeyword := args[0]\n\t\tif keyword == \"\" {\n\t\t\treturn fmt.Errorf(\"keyword is required\")\n\t\t}\n\t\tdocs := model.SearchDocs(keyword, false, nil)\n\t\tswitch outputFormat {\n\t\tcase \"json\":\n\t\t\tdata, _ := json.MarshalIndent(docs, \"\", \"  \")\n\t\t\tfmt.Println(string(data))\n\t\tdefault:\n\t\t\tif len(docs) == 0 {\n\t\t\t\tfmt.Println(\"No documents found.\")\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tw := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)\n\t\t\tfmt.Fprintln(w, \"TYPE\\tID\\tNAME\\tHPATH\")\n\t\t\tfor _, d := range docs {\n\t\t\t\ttyp, id, name := documentSearchDisplayFields(d)\n\t\t\t\tfmt.Fprintf(w, \"%s\\t%s\\t%s\\t%s\\n\", typ, id, name, d[\"hPath\"])\n\t\t\t}\n\t\t\tw.Flush()","sourceCodeStart":336,"sourceCodeEnd":372,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/cli/cmd/document.go#L336-L372","documentation":"The `document search` cobra subcommand takes a positional keyword argument (Args: cobra.MinimumNArgs(1) already guarantees at least one arg). Inside RunE, the handler reads args[0] and returns this error when the keyword is the empty string — i.e. the user passed an explicitly empty argument like `siyuan document search \"\"`. The MinimumNArgs guard cannot catch an empty-valued positional, so this check covers that gap before calling model.SearchDocs.","triggerScenarios":"Running `siyuan document search \"\"` with an explicit empty string argument; passing an unset shell variable that expands to empty: `siyuan document search \"$UNSET\"`; quoting an empty expansion; a script loop where the keyword variable is empty for one iteration.","commonSituations":"Scripting a search over a list where one element is empty; reading keywords from a file with a blank line; an env variable that was never set; assuming the command errors on zero args only (it does) but not realizing `\"\"` satisfies MinimumNArgs(1).","solutions":["Pass a non-empty keyword: `siyuan document search \"meeting\"`.","In scripts, skip empty values: `[ -n \"$kw\" ] && siyuan document search \"$kw\"`.","Trim and validate the keyword before invoking.","If reading keywords from a file, filter blank lines first."],"exampleFix":"// before\nsiyuan document search \"$KEYWORD\"   # KEYWORD unset -> \"\"\n// after\n[ -n \"$KEYWORD\" ] && siyuan document search \"$KEYWORD\"","handlingStrategy":"validation","validationCode":"# skip empty keywords when iterating\n[ -n \"$KEYWORD\" ] || { echo 'keyword is required' >&2; exit 2; }\nsiyuan document search \"$KEYWORD\"","typeGuard":"// Go: guard the positional before calling SearchDocs\nfunc nonEmptyKeyword(args []string) (string, bool) {\n    if len(args) == 0 || args[0] == \"\" { return \"\", false }\n    return args[0], true\n}","tryCatchPattern":"if ! siyuan document search \"$KEYWORD\" 2>err.txt; then\n  grep -q 'keyword is required' err.txt && echo \"pass a non-empty keyword\" >&2\n  exit 1\nfi","preventionTips":["Filter blank lines when reading keywords from a file.","Use `[ -n \"$kw\" ]` guards in loops.","Remember MinimumNArgs(1) does not reject an explicitly empty string."],"tags":["cli","cobra","validation","search","document","go"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}