multica-ai/multica · error
%s must be valid UTF-8
Error message
%s must be valid UTF-8
What it means
Content validation from skillContentBytesToString: the resolved bytes are not valid UTF-8. Skill content is transmitted as a JSON string to the API, so non-UTF-8 bytes (binary files, wrong-encoding text) cannot be carried and are rejected client-side before any network call. The label names the offending source.
Source
Thrown at server/cmd/multica/cmd_skill.go:226
if filePath != "" {
data, err := os.ReadFile(filePath)
if err != nil {
return "", false, fmt.Errorf("read file for --content-file: %w", err)
}
return skillContentBytesToString(data, "file content for --content-file")
}
if inlineSet {
return inline, true, nil
}
return "", false, nil
}
func skillContentBytesToString(data []byte, label string) (string, bool, error) {
if len(data) == 0 {
return "", false, fmt.Errorf("%s is empty", label)
}
if !utf8.Valid(data) {
return "", false, fmt.Errorf("%s must be valid UTF-8", label)
}
return string(data), true, nil
}
func runSkillList(cmd *cobra.Command, _ []string) error {
client, err := newAPIClient(cmd)
if err != nil {
return err
}
ctx, cancel := cli.APIContext(context.Background())
defer cancel()
var skills []map[string]any
if err := client.GetJSON(ctx, "/api/skills", &skills); err != nil {
return fmt.Errorf("list skills: %w", err)
}
View on GitHub (pinned to 2c0912b6ec)
Solutions
- Check the encoding: `file -i <path>`; convert with `iconv -f <src-encoding> -t UTF-8`.
- If the payload is genuinely binary, it does not belong in skill content — store it elsewhere and reference it by path/URL.
- Re-save the source file as UTF-8 in your editor before re-running the command.
Example fix
# before multica skill create --name s --content-file legacy-latin1.md # after iconv -f ISO-8859-1 -t UTF-8 legacy-latin1.md > skill.utf8.md multica skill create --name s --content-file skill.utf8.md
Defensive patterns
Strategy: validation
Validate before calling
# Reject non-UTF-8 or binary input before the CLI
case "$(file -b --mime-encoding "$CONTENT_FILE")" in utf-8|us-ascii) ;; *) echo "not UTF-8"; exit 2;; esac
# or in Go: if !utf8.Valid(data) { return errors.New("content must be UTF-8") } Type guard
func isValidSkillContent(data []byte) bool {
return len(data) > 0 && utf8.Valid(data)
} Try / catch
Match 'must be valid UTF-8'; convert encoding with iconv or exclude the binary payload, then retry — the raw bytes cannot be made valid by escaping.
Prevention
- Save source files as UTF-8.
- Never point content flags at binary assets; reference them by path instead.
- Run `file -i` on suspect files in CI before skill publish steps.
When it happens
Trigger: Passing a binary or Latin-1/CP1252-encoded file via --content-file, or piping compiled/binary output through --content-stdin.
Common situations: Assuming skill content can be any file type; text files saved in legacy encodings from Windows tools; accidentally pointing --content-file at an archive or image.
Related errors
- --content, --content-stdin, and --content-file are mutually
- read file for --content-file: %w
- %s is empty
- --name is required
- --config must be valid JSON: %w
AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15).
Data as JSON: /api/errors/535d91c22c4485e5.
Report an issue: GitHub.