{"record":{"id":"11b6347a0e3b5760","repo":"ory/hydra","slug":"message-not-found","errorCode":null,"errorMessage":"message not found","messagePattern":"message not found","errorType":"exception","errorClass":null,"httpStatus":404,"severity":"warning","filePath":"oryx/mailhog/memory.go","lineNumber":182,"sourceCode":"\tfor i := start; i > end; i-- {\n\t\t//for _, m := range memory.MessageIndex[start:end] {\n\t\tmessages = append(messages, *memory.Messages[i])\n\t}\n\n\tmsgs := data.Messages(messages)\n\treturn &msgs, nil\n}\n\n// DeleteOne deletes an individual message by storage ID\nfunc (memory *InMemory) DeleteOne(id string) error {\n\tmemory.mu.Lock()\n\tdefer memory.mu.Unlock()\n\n\tvar index int\n\tvar ok bool\n\n\tif index, ok = memory.MessageIDIndex[id]; !ok && true {\n\t\treturn errors.New(\"message not found\")\n\t}\n\n\tdelete(memory.MessageIDIndex, id)\n\tfor k, v := range memory.MessageIDIndex {\n\t\tif v > index {\n\t\t\tmemory.MessageIDIndex[k] = v - 1\n\t\t}\n\t}\n\tmemory.Messages = append(memory.Messages[:index], memory.Messages[index+1:]...)\n\treturn nil\n}\n\n// DeleteAll deletes all in memory messages\nfunc (memory *InMemory) DeleteAll() error {\n\tmemory.mu.Lock()\n\tdefer memory.mu.Unlock()\n\tmemory.Messages = make([]*data.Message, 0)\n\tmemory.MessageIDIndex = make(map[string]int)","sourceCodeStart":164,"sourceCodeEnd":200,"githubUrl":"https://github.com/ory/hydra/blob/4174065ffb052799890f7480f5360a877a67ffc1/oryx/mailhog/memory.go#L164-L200","documentation":"DeleteOne on the in-memory mailhog store returns \"message not found\" when the given message id is absent from memory.MessageIDIndex. The delete path looks up the index position first and fails fast if the id was never stored or was already deleted.","triggerScenarios":"Calling memory.DeleteOne(ctx, id) with an id that does not exist in MessageIDIndex — e.g. an id from a restarted/reseeded store, an already-deleted message, or a client-supplied id that was never valid.","commonSituations":"Double DELETE calls from a UI or test, stale message list rendered before another client deleted the message, ids issued by a previous process lifetime (memory store is not persistent).","solutions":["Check the id against the current message list (List/Search) before deleting.","Handle the error idempotently: treat \"message not found\" as success for DELETE semantics if your API allows it.","Avoid holding ids across store restarts; re-fetch the list after restart since the memory store resets.","Guard against concurrent deletes (e.g. two goroutines deleting the same id) with application-level dedup."],"exampleFix":"// before\nif err := store.DeleteOne(ctx, msgID); err != nil { return err }\n// after\nif err := store.DeleteOne(ctx, msgID); err != nil && err.Error() != \"message not found\" {\n\treturn err\n} // treat already-deleted as idempotent success","handlingStrategy":"try-catch","validationCode":"// verify the message exists before deleting\nids, _ := store.List(ctx)\nexists := false\nfor _, m := range ids {\n\tif m.ID == id { exists = true; break }\n}\nif !exists { return nil } // nothing to delete, skip call","typeGuard":null,"tryCatchPattern":"err := store.DeleteOne(ctx, id)\nif err != nil && strings.Contains(err.Error(), \"message not found\") {\n\t// idempotent DELETE: already gone, treat as success\n\treturn nil\n} else if err != nil {\n\treturn err\n}","preventionTips":["Never reuse message ids across process restarts of the memory store","Make DELETE endpoints idempotent by swallowing not-found errors","Re-fetch the message list after mutations instead of caching stale ids","Guard against duplicate concurrent deletes of the same id"],"tags":["mailhog","in-memory-store","not-found"],"backgroundTag":"resource-not-found","analyzedSha":"4174065ffb052799890f7480f5360a877a67ffc1","analyzedAt":"2026-09-03T14:52:41.581Z","contentChangedAt":"2026-09-03T14:52:41.581Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}