sipeed/picoclaw · error

apply draft failed

Error message

apply draft failed

What it means

Umbrella error from the evolution Runtime's apply step (applyCandidateDraft): the draft failed to apply via applier.applyDraftWithRollback, or post-apply persistence (SaveDrafts / SaveAppliedProfile) failed even after rollback was attempted. The real cause is appended with %v and often errors.Join-ed with audit/save errors; the draft is marked DraftStatusQuarantined and the reason is appended to draft.ScanFindings ("apply failed: ...").

Source

Thrown at pkg/evolution/runtime.go:22

	"context"
	"crypto/sha1"
	"encoding/hex"
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"sync"
	"time"
	"unicode/utf8"

	"github.com/sipeed/picoclaw/pkg/config"
	"github.com/sipeed/picoclaw/pkg/logger"
	"github.com/sipeed/picoclaw/pkg/skills"
)

var ErrApplyDraftFailed = errors.New("apply draft failed")

type RuntimeOptions struct {
	Config              config.EvolutionConfig
	Now                 func() time.Time
	Store               *Store
	Organizer           *Organizer
	PatternClusterer    PatternClusterer
	SuccessJudge        SuccessJudge
	SkillsRecaller      *SkillsRecaller
	DraftGenerator      DraftGenerator
	GeneratorFactory    func(workspace string) DraftGenerator
	SuccessJudgeFactory func(workspace string) SuccessJudge
	Applier             *Applier
	ApplierFactory      func(workspace string) *Applier
}

type Runtime struct {
	cfg                 config.EvolutionConfig

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Read the joined error chain and draft.ScanFindings — the tail after 'apply draft failed:' names the actual cause (apply error, save error, or rollback error)
  2. Verify the workspace skills directory is writable and that draft.TargetSkillName exists for update/change drafts
  3. Check the evolution store under PICOCLAW_HOME: permissions, disk space, no concurrent gateway instances (see pid file singleton)
  4. The failed draft is quarantined automatically and skipped by later runs — fix the root cause, then regenerate/re-run the evolution run instead of retrying the same quarantined draft
Defensive patterns

Strategy: try-catch

Validate before calling

// before triggering an evolution run
if err := checkWorkspaceWritable(workspaceSkillsDir); err != nil { return err }
if err := store.Load(); err != nil { return err } // store must be readable

Type guard

func isApplyDraftFailed(err error) bool {
    return errors.Is(err, evolution.ErrApplyDraftFailed)
}

Try / catch

draft, err := rt.RunEvolution(ctx) // or the apply entry point
if err != nil {
    if errors.Is(err, evolution.ErrApplyDraftFailed) {
        // inspect draft.ScanFindings for 'apply failed: ...'; draft is quarantined,
        // so fix the root cause and start a new run — do not retry the same draft
    }
    return err
}

Prevention

When it happens

Trigger: Runtime evolution run where the generated SkillDraft fails to write/scan against workspace skill files, the evolution store file is unwritable or corrupt, or the post-apply profile save fails after files changed (triggering rollback, whose error is joined too).

Common situations: Workspace skills directory read-only or skill file missing for an update draft (TargetSkillName not found); $PICOCLAW_HOME store on a full disk or with wrong ownership; draft content produced by the generator rejected by the apply-time scan; concurrent runs writing the store.

Related errors


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