You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Backend portability: Synchronous execution has no parameter-binding contract #590
Gap 3 — Synchronous execution has no parameter-binding contract
The /result request body schema includes process_graph_with_metadata, which allows declaring parameters alongside process_graph. The Defining Processes section specifies the resolution rule:
In case a parameter value is not available, the most unspecific default value from the process graph parameter definitions are used.
In practice:
At least one backend (Copernicus Data Space) rejects graphs that contain unresolved {"from_parameter": "<name>"} references at POST /result, even when the parameter has a default declared in the same request body.
The openEO Python client's Connection.download() / Connection.execute() do not forward the parameters array at all — see _build_request_with_process_graph() in the client source. So even if a backend tried to honour default-based resolution, the client strips the declaration first.
The net effect is that a graph that is valid as a UDP cannot be executed synchronously for a preview — the same graph has to be materialised into a parameter-free copy before POST /result. We shipped a client-side walker that substitutes {"from_parameter": name} with the declared default before download ([link to our implementation omitted]). That's a workable workaround but it duplicates logic the spec already describes for UDP resolution.
Suggested direction. Clarify in the /result section of the spec:
Whether backends MUST resolve {"from_parameter": ...} nodes using declared defaults when no value is provided (the current language can be read either way).
Whether backends MAY accept a runtime-value-binding mechanism at /result (e.g. a "parameter_values": {"bounding_box": {...}} sibling of "process_graph") to let the same graph run with different inputs without re-uploading it. This would close the gap with /services and UDP invocation.
If either behaviour is already intended, a one-line clarification plus a conformance test would be enough. If it's deliberately out of scope for synchronous execution, saying so explicitly would save the next person from building what we just built.
changed the title [-]Backend portability: Gap 3 — Synchronous execution has no parameter-binding contract[/-][+]Backend portability: Synchronous execution has no parameter-binding contract[/+]on Apr 29, 2026
It was never really foreseen that you send parametrized jobs to /result. But isn't the issue also present in batch jobs? There's also no way to provide values for unset parameters. The initial idea was to store the parametrized processes to /process_graphs and then send a synchronous job or batch job that uses that process and set the values for the parameters.
This becomes more clear when you think about required vs optional parameters. Usually only optional parameters have a default value and thus requiring to resolve the default value only reliably works for thise. Required parameters may not be resolvable at all. You could set a default value for a required parameter, but that doesn't really make sense logically. And I think the Web Editor may actually forbid it (tbc). This should apply to batch jobs and synchronous execution (and also web services, I think).
The specification excerpt that you quoted is in the section that describes accessing parameters when there is a child-parent relation, which is not the case in a single process graph that has a top-level parameter. Thus this actually doesn't apply for this case. Strictly speaking, I don't think there is any parameter resolving logic defined for the usecase that you are describing.
So much for the intent behind the initial specification.
Effectively this means:
A shortcut such as "parameter_values" for the /process_graphs handling could be introduced without a breaking change. This would likely apply to all three processing modes.
We could define resolving logic for process parameters, but we'd also need to solve the required parameter without a default value issue.
Alternatively, we could update the client software to resolve missing parameters and request input for them before sending to the backend. In this case, we should specify this in the spec as well.
Thanks for the clarification on design intent. The "store at /process_graphs, then reference" pattern makes sense architecturally with UDPs, but in practice (especially in notebook-based workflows) users want to iterate without managing stored UDPs registrations. The synchronous endpoint is the natural fit for that.
We've implemented option (3) as a workaround in openeo-udp: a client-side graph walker (ParameterManager.resolve()) that substitutes from_parameter references with their declared defaults before submitting to /result. It works, but it duplicates logic that ideally belongs in the spec and client libraries.
My preference would be a combination of (1) and (3):
Define parameter_values as an optional field in the /result and /jobs body to align with UDP invocation. Clients SHOULD resolve unbound from_parameter references using declared defaults as a fallback before submission.
This way the contract is clear, existing backends don't break, and the workaround we've built becomes the standardised behaviour.
Activity
[-]Backend portability: Gap 3 — Synchronous execution has no parameter-binding contract[/-][+]Backend portability: Synchronous execution has no parameter-binding contract[/+]m-mohr commentedon Apr 29, 2026
It was never really foreseen that you send parametrized jobs to /result. But isn't the issue also present in batch jobs? There's also no way to provide values for unset parameters. The initial idea was to store the parametrized processes to /process_graphs and then send a synchronous job or batch job that uses that process and set the values for the parameters.
This becomes more clear when you think about required vs optional parameters. Usually only optional parameters have a default value and thus requiring to resolve the default value only reliably works for thise. Required parameters may not be resolvable at all. You could set a default value for a required parameter, but that doesn't really make sense logically. And I think the Web Editor may actually forbid it (tbc). This should apply to batch jobs and synchronous execution (and also web services, I think).
The specification excerpt that you quoted is in the section that describes accessing parameters when there is a child-parent relation, which is not the case in a single process graph that has a top-level parameter. Thus this actually doesn't apply for this case. Strictly speaking, I don't think there is any parameter resolving logic defined for the usecase that you are describing.
So much for the intent behind the initial specification.
Effectively this means:
emmanuelmathot commentedon Apr 29, 2026
Thanks for the clarification on design intent. The "store at
/process_graphs, then reference" pattern makes sense architecturally with UDPs, but in practice (especially in notebook-based workflows) users want to iterate without managing stored UDPs registrations. The synchronous endpoint is the natural fit for that.We've implemented option (3) as a workaround in openeo-udp: a client-side graph walker (
ParameterManager.resolve()) that substitutesfrom_parameterreferences with their declared defaults before submitting to/result. It works, but it duplicates logic that ideally belongs in the spec and client libraries.My preference would be a combination of (1) and (3):
Define
parameter_valuesas an optional field in the/resultand/jobsbody to align with UDP invocation. Clients SHOULD resolve unboundfrom_parameterreferences using declared defaults as a fallback before submission.This way the contract is clear, existing backends don't break, and the workaround we've built becomes the standardised behaviour.
soxofaan commentedon Apr 29, 2026
FYI, not sure if this helps here, but the standard openeo client also has functionality to resolve/inline parameters in process graphs:
see https://open-eo.github.io/openeo-python-client/api.html#openeo.rest.connection.Connection.datacube_from_flat_graph
and usage from unit tests: https://github.com/Open-EO/openeo-python-client/blob/34ee038d024789c3d313e5c5986039539393a9de/tests/rest/datacube/test_datacube100.py#L3133-L3191