{"record":{"id":"ce0a21556f8a29ea","repo":"dgtlmoon/changedetection.io","slug":"selection-mode-must-be-either-element-or-draw","errorCode":null,"errorMessage":"Selection mode must be either \"element\" or \"draw\"","messagePattern":"Selection mode must be either \"element\" or \"draw\"","errorType":"validation","errorClass":"ValidationError","httpStatus":null,"severity":"warning","filePath":"changedetectionio/processors/image_ssim_diff/forms.py","lineNumber":40,"sourceCode":"    if not re.match(r'^\\d+,\\d+,\\d+,\\d+$', field.data):\n        raise ValidationError(_l('Bounding box must be in format: x,y,width,height (integers only)'))\n\n    # Validate values are reasonable (not negative, not ridiculously large)\n    parts = [int(p) for p in field.data.split(',')]\n    for part in parts:\n        if part < 0:\n            raise ValidationError(_l('Bounding box values must be non-negative'))\n        if part > 10000:  # Reasonable max screen dimension\n            raise ValidationError(_l('Bounding box values are too large'))\n\n\ndef validate_selection_mode(form, field):\n    \"\"\"Validate selection mode value.\"\"\"\n    if not field.data:\n        return  # Optional field\n\n    if field.data not in ['element', 'draw']:\n        raise ValidationError(_l('Selection mode must be either \"element\" or \"draw\"'))\n\n\nclass processor_settings_form(processor_text_json_diff_form):\n    \"\"\"Form for fast image comparison processor settings.\"\"\"\n\n    processor_config_min_change_percentage = IntegerField(\n        _l('Minimum Change Percentage'),\n        validators=[\n            validators.Optional(),\n            validators.NumberRange(min=1, max=100, message=_l('Must be between 0 and 100'))\n        ],\n        render_kw={\"placeholder\": \"Use global default (0.1)\"}\n    )\n\n    processor_config_pixel_difference_threshold_sensitivity = SelectField(\n        _l('Pixel Difference Sensitivity'),\n        choices=[\n                    ('', _l('Use global default'))","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/dgtlmoon/changedetection.io/blob/5d9c7c6da76340597243e8163c4f2439237fa0e8/changedetectionio/processors/image_ssim_diff/forms.py#L22-L58","documentation":"This is a WTForms ValidationError raised by the custom validator validate_selection_mode in the image_ssim_diff processor settings form. It fires when the submitted selection_mode field is non-empty but is not one of the two allowed literal values ('element' or 'draw'). It exists to stop invalid crop/selection modes from reaching the screenshot-diff processor.","triggerScenarios":"POSTing the processor settings form with selection_mode set to anything other than 'element' or 'draw' (e.g. 'freehand', 'crop', 'rect'). Only triggers when field.data is truthy — an empty value passes silently because the field is optional.","commonSituations":"Custom UI code or API clients writing the form directly; older frontends submitting a legacy mode name after an upgrade; hand-crafted curl/pytest form posts that guess the allowed values.","solutions":["Set selection_mode to exactly 'element' or 'draw' (case-sensitive, lowercase)","Leave the field empty/omitted if you don't need a selection mode","If you added a new mode in a fork, extend the allowed list in validate_selection_mode in changedetectionio/processors/image_ssim_diff/forms.py:40"],"exampleFix":"// before\nform_data = {'selection_mode': 'crop'}\n// after\nform_data = {'selection_mode': 'draw'}","handlingStrategy":"validation","validationCode":"ALLOWED = {'element', 'draw', ''}\nif form_data.get('selection_mode', '') not in ALLOWED:\n    raise ValueError(\"selection_mode must be 'element' or 'draw'\")","typeGuard":"def is_valid_selection_mode(v: str) -> bool:\n    return v in ('element', 'draw')","tryCatchPattern":null,"preventionTips":["Use a dropdown/radio with only 'element' and 'draw' in custom UIs instead of free text","Keep the field omitted when unused — empty is valid"],"tags":["wtforms","form-validation","image-ssim-diff","selection-mode"],"backgroundTag":"form-validation-failed","analyzedSha":"5d9c7c6da76340597243e8163c4f2439237fa0e8","analyzedAt":"2026-08-27T19:41:16.067Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}