{"record":{"id":"1db35b3fdf557e65","repo":"multica-ai/multica","slug":"s-is-empty","errorCode":null,"errorMessage":"%s is empty","messagePattern":"(.+?) is empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/cmd/multica/cmd_skill.go","lineNumber":223,"sourceCode":"\t\t}\n\t\treturn skillContentBytesToString(data, \"stdin content for --content-stdin\")\n\t}\n\tif filePath != \"\" {\n\t\tdata, err := os.ReadFile(filePath)\n\t\tif err != nil {\n\t\t\treturn \"\", false, fmt.Errorf(\"read file for --content-file: %w\", err)\n\t\t}\n\t\treturn skillContentBytesToString(data, \"file content for --content-file\")\n\t}\n\tif inlineSet {\n\t\treturn inline, true, nil\n\t}\n\treturn \"\", false, nil\n}\n\nfunc skillContentBytesToString(data []byte, label string) (string, bool, error) {\n\tif len(data) == 0 {\n\t\treturn \"\", false, fmt.Errorf(\"%s is empty\", label)\n\t}\n\tif !utf8.Valid(data) {\n\t\treturn \"\", false, fmt.Errorf(\"%s must be valid UTF-8\", label)\n\t}\n\treturn string(data), true, nil\n}\n\nfunc runSkillList(cmd *cobra.Command, _ []string) error {\n\tclient, err := newAPIClient(cmd)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tctx, cancel := cli.APIContext(context.Background())\n\tdefer cancel()\n\n\tvar skills []map[string]any\n\tif err := client.GetJSON(ctx, \"/api/skills\", &skills); err != nil {","sourceCodeStart":205,"sourceCodeEnd":241,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/cmd/multica/cmd_skill.go#L205-L241","documentation":"Content validation from skillContentBytesToString: the resolved content (stdin or file bytes) is zero-length. The label in the formatted message tells you which source ('stdin content for --content-stdin' or 'file content for --content-file'). Empty inline --content is not caught here (inlineSet returns the string directly), so this specifically guards byte sources.","triggerScenarios":"`multica skill create --content-stdin < /dev/null`, piping an empty string (echo -n | ...), or passing --content-file pointing at an empty (0-byte) file.","commonSituations":"Upstream generator produced no output but exited 0; redirecting from an empty placeholder file; scripting with `--content-stdin` where the heredoc collapsed.","solutions":["Verify the source actually has bytes: `wc -c < file` or test the pipe output before running multica.","Fix the upstream step that was supposed to generate the content.","If the skill genuinely has no content, omit the content flags entirely (create returns hasContent=false and the field is simply not sent)."],"exampleFix":"# before\n: > /tmp/skill.md && multica skill create --name s --content-file /tmp/skill.md\n# after\ntest -s /tmp/skill.md && multica skill create --name s --content-file /tmp/skill.md","handlingStrategy":"validation","validationCode":"# Guard both sources before the CLI runs\n[ -n \"$CONTENT_FILE\" ] && { test -s \"$CONTENT_FILE\" || { echo \"content file is empty\"; exit 2; }; }\n# for pipes: bytes=$(cat); [ -n \"$bytes\" ] || exit 2","typeGuard":null,"tryCatchPattern":"Match 'is empty' with the source label; if the producer was supposed to emit content, fix upstream and retry — do not substitute placeholder content.","preventionTips":["`test -s file` before --content-file.","Check upstream generator exit codes and output size in pipelines.","If a skill legitimately has no content, omit the flags entirely."],"tags":["go","cli","validation","skills","empty-input"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}