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
- Verify repository connectivity with `kopia repository status` and re-run the delete
- Check storage backend credentials/network and retry
- Confirm the policy still exists (`kopia policy list`) — it may have been deleted already
- 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
- Check policy existence before delete for idempotency
- Monitor storage backend health before issuing manifest writes
- Avoid concurrent policy mutations from multiple clients
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
- error writing policy manifest
- got unexpected error when loading policy item
- set global policy
- unable to find global manifest
- unable to find host-level manifest
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)