kopia/kopia · error · internalServerError

unable to delete policy

Error message

unable to delete policy

What it means

Kopia server API returns this 500 error when deleting a snapshot-source policy fails. The handler wraps policy.RemovePolicy (which reads the manifest and writes a delete of the policy manifest) inside a repo.WriteSession; any underlying storage, manifest, or validation error is re-wrapped with this message.

Solutions

  1. Verify repository connectivity with `kopia repository status` and re-run the delete
  2. Check storage backend credentials/network and retry
  3. Confirm the policy still exists (`kopia policy list`) — it may have been deleted already
  4. Retry after concurrent writers finish; manifest writes conflict-transiently

Example fix

// before
return errors.Wrap(policy.RemovePolicy(ctx, w, sourceInfo), "unable to delete policy")
// after
err := policy.RemovePolicy(ctx, w, sourceInfo)
if errors.Is(err, manifest.ErrNotFound) {
    return nil // treat as already-deleted, succeed idempotently
}
return errors.Wrap(err, "unable to delete policy")
Defensive patterns

Strategy: try-catch

Validate before calling

// Go: ensure policy exists before deleting
pol, err := policy.GetDefinedPolicy(ctx, rep, src)
if err != nil || pol == nil { /* nothing to delete; skip call */ }

Try / catch

err := repo.WriteSession(ctx, rep, opts, func(ctx, w) error {
    if err := policy.RemovePolicy(ctx, w, src); err != nil {
        if errors.Is(err, manifest.ErrNotFound) { return nil }
        return err
    }
    return nil
})
if err != nil { log.Warnf("policy delete failed: %v", err) }

Prevention

When it happens

Trigger: DELETE /api/v1/policy with a source URL whose policy manifest cannot be loaded or written; repository write session fails (storage unavailable, read-only, concurrent write conflict); RemovePolicy encounters an invalid or already-deleted policy manifest.

Common situations: Blob storage (S3/B2/fs) credentials expired or network down; repository locked by another writer; policy manifest corrupted or already removed by another client; server connected read-only.

Related errors


AI-assisted analysis of kopia/kopia@82495e54b5 (2026-09-07). Data as JSON: /api/errors/8c3fdb8a3faf63a5. Report an issue: GitHub.

Appendix: source

Thrown at internal/server/api_policies.go:121

		resp.UpcomingSnapshotTimes = append(resp.UpcomingSnapshotTimes, st)
		now = st.Add(1 * time.Second)
	}

	return resp, nil
}

func handlePolicyDelete(ctx context.Context, rc requestContext) (any, *apiError) {
	if _, ok := rc.rep.(repo.RepositoryWriter); !ok {
		return nil, repositoryNotWritableError()
	}

	sourceInfo := getSnapshotSourceFromURL(rc.req.URL)

	if err := repo.WriteSession(ctx, rc.rep, repo.WriteSessionOptions{
		Purpose: "PolicyDelete",
	}, func(ctx context.Context, w repo.RepositoryWriter) error {
		return errors.Wrap(policy.RemovePolicy(ctx, w, sourceInfo), "unable to delete policy")
	}); err != nil {
		return nil, internalServerError(err)
	}

	rc.srv.Refresh()

	return &serverapi.Empty{}, nil
}

func handlePolicyPut(ctx context.Context, rc requestContext) (any, *apiError) {
	newPolicy := &policy.Policy{}
	if err := json.Unmarshal(rc.body, newPolicy); err != nil {
		return nil, requestError(serverapi.ErrorMalformedRequest, "malformed request body")
	}

	if _, ok := rc.rep.(repo.RepositoryWriter); !ok {
		return nil, repositoryNotWritableError()
	}

View on GitHub (pinned to 82495e54b5)