JOB_INTERNAL_CWL_NULL_UNION

CWL Nullable Union Validation for job_internal State

Problem

CwlUnionParameterModel validation accepts {} (empty dict / missing parameter) for job_internal state when it should reject it. Failing test case: cwl_int_optional in parameter_specification.yml.

Background

CWL has a distinction between nullable and optional:

These are orthogonal. A parameter can be nullable but not optional (it MUST be provided, but null is an acceptable value). This is common in CWL — ["null", "int"] without a default means “you must explicitly say this is null or give me an integer.”

Current Behavior

CwlUnionParameterModel conflates these two concepts:

# parameters.py:2156-2159
@property
def request_requires_value(self) -> bool:
    if self.has_default:
        return False
    return not any(p.parameter_type == "cwl_null" for p in self.parameters)

For a ["null", "int"] union with no default:

Then in pydantic_template:

if state_representation == "job_internal":
    requires_value = self.request_requires_value and not self.has_default
    # False and True = False

Result: requires_value = False, so {} passes validation.

Why This Matters for job_internal

job_internal represents the state of a job as it’s being submitted internally within Galaxy. At this point, all parameters must have concrete values — the parameter resolution is complete. A missing parameter key means something went wrong in the pipeline, not that the user chose “no value.”

The distinction:

Proposed Fix

For job_internal, require a value whenever there’s no default, regardless of whether the union contains cwl_null:

if state_representation == "job_internal":
    requires_value = not self.has_default

request_requires_value (which incorporates the cwl_null check) remains correct for request-level validation ("request", "workflow_step") where the HTTP API needs to know if a parameter can be omitted.

Scope