{"record":{"id":"d95d049070c89fa5","repo":"theonedev/onedev","slug":"tried-to-remove-validator-that-was-not-previously","errorCode":null,"errorMessage":"Tried to remove validator that was not previously added. Make sure your validator's equals() implementation is sufficient","messagePattern":"Tried to remove validator that was not previously added\\. Make sure your validator's equals\\(\\) implementation is sufficient","errorType":"exception","errorClass":"java.lang.IllegalStateException","httpStatus":null,"severity":"error","filePath":"server-core/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java","lineNumber":575,"sourceCode":"\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse if (behavior instanceof ValidatorAdapter)\n\t\t\t{\n\t\t\t\tif (((ValidatorAdapter<?>)behavior).getValidator().equals(validator))\n\t\t\t\t{\n\t\t\t\t\tmatch = behavior;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (match != null)\n\t\t{\n\t\t\tremove(match);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tthrow new IllegalStateException(\n\t\t\t\t\"Tried to remove validator that was not previously added. \"\n\t\t\t\t\t+ \"Make sure your validator's equals() implementation is sufficient\");\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds a validator to this form component.\n\t * \n\t * @param validators\n\t *            The validator(s) to be added\n\t * @return This\n\t * @throws IllegalArgumentException\n\t *             if validator is null\n\t * @see IValidator\n\t */\n\t@SafeVarargs\n\tpublic final FormComponent<T> add(final IValidator<? super T>... validators)","sourceCodeStart":557,"sourceCodeEnd":593,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/org/apache/wicket/markup/html/form/FormComponent.java#L557-L593","documentation":"FormComponent.remove(IValidator) throws IllegalStateException when no equal validator is currently registered on the component. Wicket locates the validator via equals(), so an unequal but 'logically same' validator cannot be removed.","triggerScenarios":"Calling formComponent.remove(validator) for a validator instance that was never added, was already removed, or whose equals() does not match the added instance (e.g. new instance each time without overriding equals).","commonSituations":"Creating a fresh validator object (e.g. new StringValidator(...)) and trying to remove it while the component holds a different instance; conditional add/remove logic where add was skipped; validators added in onInitialize but removal attempted before initialize.","solutions":["Keep a reference to the exact validator instance you added and remove that same instance","Override equals() (and hashCode()) on custom validators so logically equal validators match","Guard removal with a check, or add the validator once in onInitialize and toggle behavior another way","Use component.getValidators() to confirm what is actually registered before removing"],"exampleFix":"// before\nform.add(new LengthValidator(5));\nform.remove(new LengthValidator(5)); // different instance, no equals\n// after\nprivate final LengthValidator len = new LengthValidator(5);\nform.add(len);\n...\nform.remove(len); // same instance","handlingStrategy":"validation","validationCode":"if (formComponent.getValidators().stream().noneMatch(v -> v.equals(validator))) {\n    // do not call remove(validator)\n}","typeGuard":null,"tryCatchPattern":"try {\n    formComponent.remove(validator);\n} catch (IllegalStateException e) {\n    log.debug(\"Validator not present, skipping\");\n}","preventionTips":["Store and reuse the exact validator instance added","Override equals()/hashCode() on custom validators","Check getValidators() before removing"],"tags":["wicket","form","validator"],"backgroundTag":"invalid-state-transition","analyzedSha":"d44925c47c37992c828ea673a5f9620539bc3ff2","analyzedAt":"2026-09-06T07:18:27.995Z","contentChangedAt":"2026-09-06T07:18:27.995Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}