{"record":{"id":"72130ecc327f7ef4","repo":"goharbor/harbor","slug":"precondition-72130e","errorCode":"PRECONDITION","errorMessage":"the policy %d is disabled","messagePattern":"the policy (.+?) is disabled","errorType":"error_code","errorClass":"lib/errors.Error","httpStatus":412,"severity":"error","filePath":"src/controller/replication/execution.go","lineNumber":104,"sourceCode":"\t\twp:         lib.NewWorkerPool(10),\n\t}\n}\n\ntype controller struct {\n\trepMgr     replication.Manager\n\texecMgr    task.ExecutionManager\n\ttaskMgr    task.Manager\n\tregMgr     reg.Manager\n\tscheduler  scheduler.Scheduler\n\tflowCtl    flow.Controller\n\tormCreator orm.Creator\n\twp         *lib.WorkerPool\n}\n\nfunc (c *controller) Start(ctx context.Context, policy *replicationmodel.Policy, resource *model.Resource, trigger string) (int64, error) {\n\tlogger := log.GetLogger(ctx)\n\tif !policy.Enabled {\n\t\treturn 0, errors.New(nil).WithCode(errors.PreconditionCode).\n\t\t\tWithMessagef(\"the policy %d is disabled\", policy.ID)\n\t}\n\t// create an execution record\n\textra := make(map[string]any)\n\tif op := operator.FromContext(ctx); op != \"\" {\n\t\textra[\"operator\"] = op\n\t}\n\n\tvar count int64\n\t// If running executions are found, skip the current execution and mark it as error.\n\tif policy.SingleActiveReplication {\n\t\tvar err error\n\t\tcount, err = c.execMgr.Count(ctx, &q.Query{\n\t\t\tKeywords: map[string]any{\n\t\t\t\t\"VendorType\": job.ReplicationVendorType,\n\t\t\t\t\"VendorID\":   policy.ID,\n\t\t\t\t\"Status\":     job.RunningStatus.String(),\n\t\t\t},","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/goharbor/harbor/blob/7b2fd08cc568955cca339afeefab27372840d936/src/controller/replication/execution.go#L86-L122","documentation":"Thrown by the replication controller's Start() (src/controller/replication/execution.go:104) when a replication execution is requested for a policy whose Enabled flag is false. It is returned before any execution record or task is created. The PRECONDITION code maps to HTTP 412, telling the caller the policy must be enabled before it can run.","triggerScenarios":"POST /api/v2.0/replication/executions with {\"policy_id\": N} where policy N has enabled=false; or calling replication.Controller.Start(ctx, policy, ...) with a policy fetched before another admin disabled it.","commonSituations":"Triggering a replication manually from automation/CI that assumes the policy is active; a policy disabled by a retention/cleanup script or another administrator; UI user clicking 'Replicate' on a stopped policy; race where the policy was disabled between fetch and start.","solutions":["Enable the policy first: PUT /api/v2.0/replication/policies/{id} with {\"enabled\": true}, then retry the execution request","Fetch the policy immediately before starting and verify enabled=true, or re-fetch on 412 and retry once","Fix automation scripts that hard-code policy IDs of policies that were later disabled"],"exampleFix":"// before\nPOST /api/v2.0/replication/executions\n{\"policy_id\": 7}   // 412: the policy 7 is disabled\n\n// after\nPUT /api/v2.0/replication/policies/7\n{\"enabled\": true}\n\nPOST /api/v2.0/replication/executions\n{\"policy_id\": 7}","handlingStrategy":"validation","validationCode":"policy, err := apiClient.GetReplicationPolicy(policyID)\nif err != nil {\n    return err\n}\nif !policy.Enabled {\n    // enable first: PUT /replication/policies/%d with {\"enabled\": true}\n    return fmt.Errorf(\"policy %d disabled; enable before starting\", policyID)\n}\nreturn apiClient.StartReplication(policyID)","typeGuard":"func isPolicyDisabledErr(err error) bool {\n    return errors.IsErr(err, errors.PreconditionCode) &&\n        strings.Contains(err.Error(), \"is disabled\")\n}","tryCatchPattern":"if _, err := replicationCtl.Start(ctx, policy, res, trigger); err != nil {\n    if errors.IsErr(err, errors.PreconditionCode) && strings.Contains(err.Error(), \"is disabled\") {\n        // enable policy, retry once\n    }\n    return err\n}","preventionTips":["Always GET the policy and check .Enabled immediately before triggering an execution","Give automation a re-fetch-and-retry-once path for 412 responses","Alert when a replication policy is disabled so triggers do not fail silently"],"tags":["harbor","replication","policy","precondition","api"],"backgroundTag":null,"analyzedSha":"7b2fd08cc568955cca339afeefab27372840d936","analyzedAt":"2026-08-16T00:00:10.961Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}