multica-ai/multica · error
read skill archive: %w
Error message
read skill archive: %w
What it means
Returned by `multica skill import --file <path>` when `os.ReadFile` on the local archive fails. The wrapped error is a standard Go filesystem error: `no such file or directory`, `permission denied`, or `is a directory`. This happens before any bytes hit the network.
Source
Thrown at server/cmd/multica/cmd_skill.go:476
switch {
case importURL == "" && importFile == "":
return fmt.Errorf("either --url or --file is required")
case importURL != "" && importFile != "":
return fmt.Errorf("--url and --file are mutually exclusive")
}
onConflict, _ := cmd.Flags().GetString("on-conflict")
if !validSkillImportConflictStrategy(onConflict) {
return fmt.Errorf("--on-conflict must be one of: fail, overwrite, rename, skip")
}
ctx, cancel := context.WithTimeout(context.Background(), cli.AtLeastAPITimeout(60*time.Second))
defer cancel()
var result map[string]any
if importFile != "" {
fileData, readErr := os.ReadFile(importFile)
if readErr != nil {
return fmt.Errorf("read skill archive: %w", readErr)
}
if err := client.ImportSkillFile(ctx, fileData, filepath.Base(importFile), onConflict, &result); err != nil {
if handledErr := handleSkillImportError(cmd, err); handledErr != nil {
return handledErr
}
return fmt.Errorf("import skill: %w", err)
}
return printSkillImportResult(cmd, result)
}
body := map[string]any{
"url": importURL,
"on_conflict": onConflict,
}
if err := client.PostJSON(ctx, "/api/skills/import", body, &result); err != nil {
if handledErr := handleSkillImportError(cmd, err); handledErr != nil {
return handledErr
}View on GitHub (pinned to 2c0912b6ec)
Solutions
- Verify the file exists and is readable at that exact path: `ls -la <path>` from the same shell/cwd.
- Use an absolute path to eliminate cwd ambiguity.
- Expand `~` yourself (`$HOME/Downloads/skill.zip`) if the path was quoted.
- Check permissions if ls shows the file but ReadFile still fails (`chmod +r` or adjust ownership).
Example fix
# before multica skill import --file skill.zip # wrong cwd # after multica skill import --file "$(pwd)/downloads/skill.zip"
Defensive patterns
Strategy: validation
Validate before calling
test -f "$ARCHIVE" || { echo "archive not found: $ARCHIVE"; exit 1; }
test -r "$ARCHIVE" || { echo "archive unreadable: $ARCHIVE"; exit 1; }
multica skill import --file "$(realpath "$ARCHIVE")" Try / catch
If the read still fails inside the CLI, inspect errno in the wrapped message: ENOENT → fix path/cwd; EACCES → fix permissions; EISDIR → point at the archive file itself.
Prevention
- Always pass an absolute path (realpath) to imports in scripts.
- Expand ~ explicitly ($HOME) — quoting suppresses tilde expansion.
- Download artifacts to a known directory and reference that path.
When it happens
Trigger: Passing a path that does not exist (typo, wrong cwd since relative paths resolve against the current directory); pointing at a directory instead of the archive file; file unreadable due to ownership/permissions; path with unexpanded `~` (the shell does not expand `~/…` inside quotes).
Common situations: Running the CLI from a different working directory than where the archive was downloaded; CI runner checking out the repo without the artifact; `"~/Downloads/skill.zip"` quoted so tilde never expands; permission mismatch when running under a different user or container.
Related errors
- file not found: %w
- unsupported file format %q: must be .png, .jpg, .jpeg, .gif,
- --%s-file %q: empty contents%s
- plugin directory %q is not empty
- plugin source %q is not a directory or regular ZIP
AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15).
Data as JSON: /api/errors/69c9583ea4fb7b00.
Report an issue: GitHub.