sipeed/picoclaw · error
✗ failed to persist skill metadata: %w
Error message
✗ failed to persist skill metadata: %w
What it means
The skill files installed, but writing the origin metadata (.skill-origin.json under the skill directory, written atomically via fileutil.WriteFileAtomic) failed — a marshal error or a disk write failure. The install is rolled back with os.RemoveAll so nothing half-installed remains.
Source
Thrown at cmd/picoclaw/internal/skills/helpers.go:124
if !workspaceHasValidSkillDirectory(workspace, dirName) {
_ = os.RemoveAll(targetDir)
return fmt.Errorf("✗ failed to install skill: registry archive for %q is not a valid skill", target)
}
normalizedSlug, registryURL := skills.BuildInstallMetadataForRegistryInstance(registry, target, result.Version)
installedAt := time.Now().UnixMilli()
if err := writeInstalledSkillOriginMeta(targetDir, installedSkillOriginMeta{
Version: 1,
OriginKind: "third_party",
Registry: registry.Name(),
Slug: normalizedSlug,
RegistryURL: registryURL,
InstalledVersion: result.Version,
InstalledAt: installedAt,
}); err != nil {
_ = os.RemoveAll(targetDir)
return fmt.Errorf("✗ failed to persist skill metadata: %w", err)
}
fmt.Printf("\u2713 Skill '%s' v%s installed successfully!\n", dirName, result.Version)
if result.Summary != "" {
fmt.Printf(" %s\n", result.Summary)
}
return nil
}
func writeInstalledSkillOriginMeta(targetDir string, meta installedSkillOriginMeta) error {
data, err := json.MarshalIndent(meta, "", " ")
if err != nil {
return err
}
return fileutil.WriteFileAtomic(filepath.Join(targetDir, ".skill-origin.json"), data, 0o600)
}
View on GitHub (pinned to 49183d7e8d)
Solutions
- Check free space and quota on the workspace filesystem (df and quota).
- Verify write permission on <workspace>/skills/<dirName>.
- Retry after freeing space or remounting; the rollback makes retries safe.
- If it recurs on a single machine, check antivirus/filesystem-watcher interference.
Defensive patterns
Strategy: retry
Validate before calling
probe := filepath.Join(workspace, ".meta-write-probe")
if err := os.WriteFile(probe, []byte("ok"), 0o644); err != nil {
return fmt.Errorf("workspace not writable: %w", err)
}
os.Remove(probe) Try / catch
if err := writeInstalledSkillOriginMeta(targetDir, meta); err != nil {
if isTransientFS(err) { // EIO, ENOSPC cleared after cleanup
return retryWithBackoff()
}
return fmt.Errorf("failed to persist skill metadata: %w", err)
} Prevention
- Monitor free space on the filesystem hosting the workspace.
- Keep the workspace off network mounts where possible.
- Retry the install once — the automatic rollback makes retries safe.
When it happens
Trigger: Disk full or quota exceeded, write permission lost mid-install, or the freshly created targetDir removed/locked concurrently, causing writeInstalledSkillOriginMeta to fail at helpers.go:124.
Common situations: Disk quota exhausted during install, an antivirus/filesystem watcher locking the new directory on some platforms, or the workspace on a flaky network mount.
Related errors
- ✗ skill '%s' already installed at %s
- ✗ failed to create skills directory: %w
- create output dir: %w
- write result: %w
- failed to save config: %w
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/b1fad83e8daf50cb.
Report an issue: GitHub.