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

  1. Check free space and quota on the workspace filesystem (df and quota).
  2. Verify write permission on <workspace>/skills/<dirName>.
  3. Retry after freeing space or remounting; the rollback makes retries safe.
  4. 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

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


AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15). Data as JSON: /api/errors/b1fad83e8daf50cb. Report an issue: GitHub.