dgtlmoon/changedetection.io · warning · ValidationError

A variable or function is not defined: {e}

Error message

A variable or function is not defined: {e}

What it means

Raised by a WTForms custom validator in changedetectionio when a notification body template references a Jinja2 variable or function that is undefined at render time. The validator renders the joined notification fields with jinja2_env.from_string(...).render() and catches jinja2.exceptions.UndefinedError, converting it into a wtforms.ValidationError so the form rejects the input. It means the template syntax is fine but a name used inside {{ ... }} or {% ... %}} does not exist in the rendering context.

Source

Thrown at changedetectionio/forms.py:595

        # Might be a list of text, or might be just text (like from the apprise url list)
        joined_data = ' '.join(map(str, field.data)) if isinstance(field.data, list) else f"{field.data}"

        try:
            # Use the shared helper to create a properly configured environment
            jinja2_env = create_jinja_env(loader=BaseLoader)

            # Add notification tokens for validation
            static_token_placeholders = NotificationContextData()
            static_token_placeholders.set_random_for_validation()
            jinja2_env.globals.update(static_token_placeholders)
            if hasattr(field, 'extra_notification_tokens'):
                jinja2_env.globals.update(field.extra_notification_tokens)

            jinja2_env.from_string(joined_data).render()
        except TemplateSyntaxError as e:
            raise ValidationError(f"This is not a valid Jinja2 template: {e}") from e
        except UndefinedError as e:
            raise ValidationError(f"A variable or function is not defined: {e}") from e
        except jinja2.exceptions.SecurityError as e:
            raise ValidationError(f"This is not a valid Jinja2 template: {e}") from e

        # Check for undeclared variables
        ast = jinja2_env.parse(joined_data)
        undefined = ", ".join(find_undeclared_variables(ast))
        if undefined:
            raise ValidationError(
                f"The following tokens used in the notification are not valid: {undefined}"
            )

class validateURL(object):

    """
       Flask wtform validators wont work with basic auth
    """

    def __init__(self, message=None):

View on GitHub (pinned to 5d9c7c6da7)

Solutions

  1. Check the notification token list (extra_notification_tokens) and correct the token name / typo in the template
  2. Remove or wrap the offending variable with a default filter, e.g. {{maybe_missing|default('')}}
  3. If you extended the code, register the missing function/variable in jinja2_env.globals before validation runs

Example fix

# before
{{current_diff}}
# after
{{current_diff|default('')}}
Defensive patterns

Strategy: validation

Validate before calling

import jinja2
from jinja2.meta import find_undeclared_variables

def template_tokens_ok(template: str, allowed_tokens: set[str]) -> list[str]:
    env = jinja2.Environment(undefined=jinja2.StrictUndefined)
    ast = env.parse(template)
    missing = find_undeclared_variables(ast) - allowed_tokens
    try:
        env.from_string(template).render({t: '' for t in allowed_tokens})
    except jinja2.UndefinedError:
        return ['runtime-undefined']
    return sorted(missing)

Try / catch

try:
    validate_notification_template(text)
except wtforms.ValidationError as e:
    # show 'A variable or function is not defined: ...' to the user
    report(e.message)

Prevention

When it happens

Trigger: Submitting a watch/notification form whose title or body uses a token like {{current_diff}} or a filter/function that is not registered in jinja2_env.globals (only field.extra_notification_tokens are injected). Any Jinja2 UndefinedError raised while rendering joined_data triggers this ValidationError.

Common situations: Typos in notification tokens ({{curent_diff}} instead of {{current_diff}}), using tokens only available in a different notification system (e.g. AppRise tokens), or calling a helper function that was never registered in jinja2_env.globals.

Related errors


AI-assisted analysis of dgtlmoon/changedetection.io@5d9c7c6da7 (2026-08-27). Data as JSON: /api/errors/375ee7a4d4337ab8. Report an issue: GitHub.