Skip to content

Backend portability: Synchronous execution has no parameter-binding contract #590

Open

Description

@emmanuelmathot

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:

  1. 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.
  2. 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.

Activity

  1. 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
  2. m-mohr commented on Apr 29, 2026

    @m-mohr
    Member

    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:

    1. 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.
    2. We could define resolving logic for process parameters, but we'd also need to solve the required parameter without a default value issue.
    3. 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.
    4. Any other options?
  3. added this to the 1.4.0 milestone on Apr 29, 2026
  4. emmanuelmathot commented on Apr 29, 2026

    @emmanuelmathot
    Author

    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.

  5. soxofaan commented on Apr 29, 2026

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions