Skip to content

Fix: validate automation config keys - #2563

Draft
BelhsanHmida wants to merge 4 commits into
mainfrom
fix/2498-validate-automation-config-keys
Draft

BelhsanHmida wants to merge 4 commits into
mainfrom
fix/2498-validate-automation-config-keys

Conversation

@BelhsanHmida

@BelhsanHmida BelhsanHmida commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

Description

  • A mistake in a data generator's config was reported against parameters, for forecast and report automations alike, sending the caller looking for a mistake in a part of the request that was fine. The create endpoint wrapped every ValidationError from the service as {"parameters": ...}, discarding which schema had failed.
  • A scheduling automation accepted config and data-generator with 201 Created and silently ignored both. It now refuses each by name with a 422: a schedule automation's scheduler, and the flex config it runs under, follow from the asset and its flex context, so accepting either would record a choice that nothing goes on to read.
  • A report automation without a reporter raised a bare string, naming no field. It is now reported under data-generator.
  • An unsupported automation type is now reported under type.
  • Added an errors_reported_for(section) context manager in flexmeasures/data/services/automations.py, which re-raises a ValidationError keyed by the section it came from, and wrapped each raise site with the section it belongs to: the window check, the forecast and report parameter loads, the forecast window resolution, the schedule trigger message and the schedule sensor resolution report against parameters; the forecaster and reporter setups report against config.
  • Three error paths that reached the caller unkeyed are now keyed as parameters: the unknown-field error from AssetTriggerSchema (raised inside resolve_schedule_automation_sensors, whose docstring already promised the caller would report it against the parameters), the bare messages from validate_automation_window, and the offset and window errors from resolve_automation_window, which was evaluated as an argument and so sat outside the wrapper.
  • flexmeasures add automation now reports "Invalid automation:" instead of "Invalid parameters:", since the fault is not always in the parameters, and the keyed messages now say where it is.
  • The scheduling rejection lives in refuse_fields_a_schedule_automation_cannot_use, so that create_automation stays within the C901 complexity budget.

This is not a breaking change. A client parsing message.json.parameters will find config errors under message.json.config, but the automation endpoints landed in v3.0-37 and v3.0-38, both inside the unreleased v1.1.0, so no released client can be parsing this shape.

The issue predates #2297 and #2536 and is partly out of date: unknown parameters keys were already rejected with a field-specific 422, with nothing persisted. Criterion 6 is covered by a new test rather than by new code.

  • Added changelog item in documentation/changelog.rst

Look & Feel

Before, a forecast automation with a bad config key:

{"message": {"json": {"parameters": {"not-a-config-field": ["Unknown field."]}}}}

After:

{"message": {"json": {"config": {"not-a-config-field": ["Unknown field."]}}}}

Before, a schedule automation sent a config and a data-generator:

201 Created

After:

{"message": {"json": {
  "config": ["A schedule automation configures no data generator of its own: its scheduler and flex config follow from the asset and its flex context."],
  "data-generator": ["A schedule automation does not choose a data generator: its scheduler follows from the asset."]
}}}

Before, a report automation with no reporter:

{"message": {"json": {"parameters": ["A reporter is required for report automations (e.g. PandasReporter)."]}}}

After:

{"message": {"json": {"data-generator": ["A reporter is required for report automations (e.g. PandasReporter)."]}}}

On the command line:

$ flexmeasures add automation --asset 1 --name "Bad forecaster config" --cron "0 6 * * *" --sensor 1 --config config.yml
Invalid forecast automation: {'config': {'not-a-config-field': ['Unknown field.']}}
Aborted!

How to test

pytest flexmeasures/api/v3_0/tests/test_automations_api.py
pytest flexmeasures/cli/tests/test_automations.py
pytest flexmeasures/data/tests/

New tests:

  • test_post_automation_reports_a_config_error_against_the_config — forecasting and reporting; the error is keyed config and no parameters key is present.
  • test_post_automation_reports_a_parameter_error_against_the_parameters — forecasting, reporting and scheduling; the error is keyed parameters and no config key is present.
  • test_post_schedule_automation_rejects_a_data_generator_and_its_config — each field is refused by name, and nothing is persisted.
  • test_post_report_automation_without_a_reporter_names_the_field_to_fill_in — keyed data-generator.
  • test_a_refused_automation_leaves_nothing_behind — three failing requests leave the Automation, DataSource and AssetAuditLog row counts unchanged.
  • test_add_forecast_automation_reports_a_config_error_against_the_config — the CLI equivalent.

Updated: seven CLI tests asserted the old wording, "Invalid parameters", which contradicts itself once the messages can name the config instead. They now assert the new wording and the key the message is reported under.

Each new test was proven to fail before it was called done:

What was broken What went red
The endpoint re-wraps as {"parameters": e.messages} again the two config tests, the two schedule-rejection tests and the reporter-less test
errors_reported_for("parameters") renamed to "mislabelled" all three parameter tests, including the scheduling one
The CLI string put back to "Invalid <noun> parameters" all eight CLI tests
An audit record written before validation, and committed on the way out of the 422 test_a_refused_automation_leaves_nothing_behind

Each break was restored and the suite re-run.

Full suites, run one at a time: flexmeasures/api/v3_0/tests/ 518 passed; flexmeasures/cli/tests/ 234 passed, 1 xfailed; flexmeasures/data/tests/ 389 passed.

Further Improvements

Merge order: #2554 should merge first. Main's "New automation" form shows the Data generator and Config fields for every automation type; #2554 gates them so that a schedule automation sends neither. Without that gating, this PR's new rejection turns leftover text in a hidden field into a 422 as soon as the user picks scheduling.

The API changelog section here is numbered against #2554's v3.0-38. If this PR lands first, renumber it to v3.0-38.

Related Items

Closes #2498.


Sign-off

  • I agree to contribute to the project under Apache 2 License.
  • To the best of my knowledge, the proposed patch is not based on code under GPL or other license that is incompatible with FlexMeasures

… is at fault

Context:
- Issue #2498: a mistake in a data generator's config was reported against
  "parameters", sending the caller looking in a part of the request that was fine.
- A scheduling automation accepted a config and a data-generator with 201 Created,
  and silently ignored both.
- A report automation without a reporter raised a bare string, naming no field at all.

Change:
- Added an `errors_reported_for(section)` context manager, which re-raises a
  ValidationError keyed by the section it came from.
- Wrapped each raise site with the section it belongs to: the window check, the
  forecast and report parameter loads, the schedule trigger load and the schedule
  sensor resolution report against "parameters"; the forecaster and reporter setups
  report against "config".
- A scheduling automation now refuses a non-empty config or data-generator by name,
  in `refuse_fields_a_schedule_automation_cannot_use`: its scheduler and flex config
  follow from the asset.
- A missing reporter is reported against "data-generator", and an unsupported
  automation type against "type".
- The create endpoint returns the service's messages as they are, rather than
  re-wrapping every one of them as {"parameters": ...}.
- The CLI reads "Invalid <noun> automation:", since the fault is not always in the
  parameters, and the keyed messages now say where it is.

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Context:
- The create endpoint and `flexmeasures add automation` now key each validation
  error by the part of the request it came from (issue #2498).
- Seven CLI tests asserted the old wording, "Invalid <noun> parameters", which
  contradicts itself once the messages can name the config instead.

Change:
- Added API tests: a config error is keyed "config" and a parameter error
  "parameters" (forecasting and reporting, plus scheduling for the parameters);
  a scheduling automation refuses "config" and "data-generator" by name; a report
  automation without a reporter is keyed "data-generator"; and three refused
  requests leave the automation, data source and audit log counts unchanged.
- Added a CLI test for a forecaster config error keyed "config".
- Updated the CLI tests that asserted the old wording to assert the new one, plus
  the key the message is now reported under.

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
…t fault

Context:
- PR #2563 changes which key an automation's validation errors are reported under,
  which an API client reads.

Change:
- Added an entry to the "Automations, in detail" section of the main changelog,
  rather than to Bugfixes, since automations have not shipped in a release yet.
- Added a v3.0-39 section to the API change log, saying explicitly that this is not
  a breaking change, as the automation endpoints are not part of a release.
- Numbered v3.0-39 against PR #2554's v3.0-38, which merges first.

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
Context:
- PR #2542 landed on main, and adds `_stored_sensor_id` to
  `flexmeasures/data/services/automations.py` in the same place this branch adds
  `refuse_fields_a_schedule_automation_cannot_use` and `errors_reported_for`.

Change:
- Resolved the add/add conflict by keeping both sides: this branch's two helpers,
  then main's `_stored_sensor_id`, which main placed just above
  `_prepare_forecast_automation`.
- Everything else merged cleanly, including `_prepare_forecast_automation`, where
  main's SensorReference unwrap now follows this branch's wrapped parameter load.

Signed-off-by: Mohamed Belhsan Hmida <mohamedbelhsanhmida@gmail.com>
@read-the-docs-community

read-the-docs-community Bot commented Sep 17, 2026

Copy link
Copy Markdown

Documentation build overview

📚 flexmeasures | 🛠️ Build #34622066 | 📁 Comparing 7d3b29e against latest (4f45c65)

  🔍 Preview build  

5 files changed · ± 5 modified

± Modified

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Validate automation config and parameter keys before persisting

1 participant