fix: safe-empty restock default so restock notification tokens work for any watch - #4249
#4249Merged
dgtlmoon merged 2 commits intoJul 13, 2026
dgtlmoon:masterdgtlmoon/changedetection.io:masterfrom
ebarkhordar:fix/3490-restock-token-safe-emptyebarkhordar/changedetection.io:fix/3490-restock-token-safe-emptyCopy head branch name to clipboard
Merged
fix: safe-empty restock default so restock notification tokens work for any watch#4249dgtlmoon merged 2 commits intodgtlmoon:masterdgtlmoon/changedetection.io:masterfrom ebarkhordar:fix/3490-restock-token-safe-emptyebarkhordar/changedetection.io:fix/3490-restock-token-safe-emptyCopy head branch name to clipboard
dgtlmoon merged 2 commits into
dgtlmoon:masterdgtlmoon/changedetection.io:masterfrom
ebarkhordar:fix/3490-restock-token-safe-emptyebarkhordar/changedetection.io:fix/3490-restock-token-safe-emptyCopy head branch name to clipboard
Conversation
The {{ restock.price }} family of notification tokens is only injected for
restock watches (processors/restock_diff extra_notification_token_values()).
For a non-restock or system-wide notification body the `restock` token was
absent from NotificationContextData's default set, so it raised UndefinedError
at send time and failed save-time template validation.
Add a safe-empty 'restock': {} default. Restock watches still override it with
real price data; every other watch now renders the token as empty instead of
crashing, and system-wide bodies validate. Fixes dgtlmoon#3490.
Owner
|
yeah this should be solved as part of a bigger refactor, but this is a good enough fix for now , thanks |
dgtlmoon
reviewed
Jul 13, 2026
Contributor
Author
|
Thanks for merging. Agreed, the storage refactor is the right long term home for this, glad the small fix covers the gap until then. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Root cause
{{ restock.price }}(and the otherrestock.*tokens) are only added to thenotification context for restock watches, in
processors/restock_diffextra_notification_token_values(). The base token set inNotificationContextData.__init__(changedetectionio/notification_service.py) has norestockkey, so for a non-restock watch, or for a system-wide notification body, thetoken is undefined. That produces two failures:
{{ restock.price }}for a non-restock watchraises
jinja2 UndefinedError: 'restock' is undefined(the exact error in 'restock' is undefined #3490).ValidateJinja2Templatebuilds its valid-token set from the same defaults,so a system-wide body using
{{ restock.price }}is rejected unless a restock watchhappens to exist.
Invariant
A notification token that is valid in a per-watch body should also be a valid,
non-crashing token in a system-wide body, independent of the current watch inventory.
Fix
Add a safe-empty
'restock': {}to theNotificationContextDatadefault token set.Restock watches still override it with the real price object via
extra_notification_token_values(), so their notifications are unchanged. Every otherwatch now renders
{{ restock.price }}as empty rather than raising, and system-widebodies validate.
This is intentionally the narrow token-availability fix for #3490, not the separate
restock-data storage change noted in the issue thread.
How I verified
In a clean
python:3.11-slimDocker container againstmasterHEAD (ee84ece):master:render('{{ restock.price }}', **NotificationContextData())raises
UndefinedError, andValidateJinja2TemplateraisesValidationError, both'restock' is undefined.tests/test_notification_restock_token.pycovering the default token, thesend-time render, and the save-time validation. It fails on
master(3 failed) andpasses with the fix (3 passed).
tests/llm/test_notification_tokens.pyandtests/llm/test_llm_restock_plugin.pywith the fix: 36 passed.I did not run the full browser/selenium/playwright suite or the SMTP integration tests;
this change only touches the in-memory default token dict.
Run:
pytest tests/test_notification_restock_token.pyAI assistance was used to help write this change; I reproduced and verified it as
described above.
Fixes #3490