{"record":{"id":"d7b2a07d84644884","repo":"Netflix/chaosmonkey","slug":"schedule-already-exists","errorCode":null,"errorMessage":"schedule already exists","messagePattern":"schedule already exists","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"schedstore/schedstore.go","lineNumber":26,"sourceCode":"//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\npackage schedstore\n\nimport (\n\t\"errors\"\n\t\"time\"\n\n\t\"github.com/Netflix/chaosmonkey/v2/schedule\"\n)\n\n// ErrAlreadyExists is returned when calling Publish if a schedule already\n// exists\nvar ErrAlreadyExists = errors.New(\"schedule already exists\")\n\n// SchedStore stores schedule of terminations\ntype SchedStore interface {\n\t// Retrieve retrieves the schedule for the given date\n\t// The date must be in the local time zone\n\tRetrieve(date time.Time) (*schedule.Schedule, error)\n\n\t// Publish publishes the schedule for the given date\n\t// The date must be in the local time zone\n\tPublish(date time.Time, sched *schedule.Schedule) error\n}\n","sourceCodeStart":8,"sourceCodeEnd":38,"githubUrl":"https://github.com/Netflix/chaosmonkey/blob/eaa28fb761c0ebe8644d1333e5d164e9cc3071e9/schedstore/schedstore.go#L8-L38","documentation":"ErrAlreadyExists is the sentinel error returned by SchedStore.Publish (and PublishWithDelay) when a chaos-monkey termination schedule for the given date already exists in the store. The MySQL implementation detects a duplicate during the insert transaction and returns this sentinel even if the transaction commit itself fails, per the comment at mysql/mysql.go:164. It lets callers distinguish 'already published' from other storage failures.","triggerScenarios":"Calling schedstore.Publish or PublishWithDelay for a date for which a schedule row already exists in the MySQL sched table; concurrent Publish calls racing to insert the same date's schedule.","commonSituations":"A scheduler cron job running twice on the same day; re-running an outbox/dispatch process after a partial failure; two instances of the chaos monkey coordinator both attempting to publish the daily schedule.","solutions":["Check for existence first or treat ErrAlreadyExists as an expected no-op: use errors.Is(err, schedstore.ErrAlreadyExists) and skip/continue","Run only one scheduler instance at a time (lock or leader election) to avoid duplicate publishes","If a stale duplicate must be replaced, delete the existing schedule row for that date before republishing"],"exampleFix":"// before\nif err := store.Publish(sched); err != nil {\n    log.Fatal(err)\n}\n// after\nif err := store.Publish(sched); err != nil {\n    if errors.Is(err, schedstore.ErrAlreadyExists) {\n        log.Println(\"schedule already published for today; skipping\")\n        return nil\n    }\n    log.Fatal(err)\n}","handlingStrategy":"try-catch","validationCode":"var exists bool\nerr := db.QueryRow(\"SELECT EXISTS(SELECT 1 FROM sched WHERE schedDate=?)\", date.Format(\"2006-01-02\")).Scan(&exists)\nif err == nil && exists { return nil // skip publish }","typeGuard":"func IsAlreadyExists(err error) bool { return errors.Is(err, schedstore.ErrAlreadyExists) }","tryCatchPattern":"if err := store.Publish(sched); err != nil {\n    if errors.Is(err, schedstore.ErrAlreadyExists) {\n        // expected: schedule for this date already published\n        return nil\n    }\n    return err\n}","preventionTips":["Make publishing idempotent: always handle ErrAlreadyExists explicitly with errors.Is","Run a single scheduler instance or use a lock/leader election so only one process publishes per date","Add a UNIQUE constraint on the schedule date so the DB enforces the invariant","Log ErrAlreadyExists at info level, not as a failure"],"tags":["go","mysql","duplicate-insert","sentinel-error"],"backgroundTag":"duplicate-record-conflict","analyzedSha":"eaa28fb761c0ebe8644d1333e5d164e9cc3071e9","analyzedAt":"2026-09-03T17:04:39.020Z","contentChangedAt":"2026-09-03T17:04:39.020Z","schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}