View a markdown version of this page

WDL engine change log for HealthOmics - AWS HealthOmics

WDL engine change log for HealthOmics

This page contains change log for WDL engine for both WDL strict mode and WDL lenient mode. Each section summarizes new features, enhancements, and deprecations.

New features and enhancements

The following table lists new features and enhancements for the WDL engine on HealthOmics.

Date of Change Change Name Change Description Recommended Action
September 22, 2026 Consistent CRLF line-ending handling

HealthOmics trims Windows-style (\r\n) line endings consistently across read_lines(), read_tsv(), and read_map(), matching the behavior of standard Linux tools.

None. There are no workflow changes required.
September 22, 2026

zip(), cross(), and read_tsv() now correctly handle mixed-type inputs. manual type-cast workarounds can be removed.

The built-in functions zip(), cross(), and read_tsv() now correctly infer the types of their return values. In previous versions, these functions could produce unexpected type errors when combining mixed types (for example, Array[String] and Array[Int] in a zip() call), requiring manual type-cast workarounds in WDL code.

If your workflow includes explicit type casts added to work around type errors from zip(), cross(), or read_tsv(), you can remove them. HealthOmics now infers the correct types automatically.

Keeping existing type casts will not cause any errors or affect workflow behavior.

September 22, 2026

basename(path, "") fix returns the filename instead of and empty string.

basename(path, "") now returns the file name.

For example, basename("/path/to/file.txt", "") will return "file.txt" instead of an empty string.

Search your workflows for basename(x, "") calls. If any exist, verify that returning the filename is the expected behavior.

September 22, 2026

Float-key collision detection in collect_by_key()

collect_by_key() previously treated Float keys as identical if they matched to 6 decimal places. Distinct values such as 0.0000001 and 0.0000002 were merged into one group.

From the change date onwards, HealthOmics detects this collision at workflow creation time and fail the workflow with a clear error in GetWorkflow statusMessage field instead of discarding results.

A workflow that previously completed successfully while merging distinct Float keys will now fail with a collision detection error like "statusMessage": "(collect_by_key_test.wdl Ln 17 Col 47) No such function: collect_by_key\n Map[Float, Array[String]] collected = collect_by_key(pairs_with_collision)"

You can use any of the three approaches:

  • Use String keys: Change Array[Pair[Float, String]] to Array[Pair[String, String]] and quote your key values. String keys are always distinct and eliminate the collision risk entirely.

  • Use Int keys: Change the key type to Array[Pair[Int, String]] Multiply your float values by a power of 10 to preserve the required precision as integers.

  • If Float keys are unavoidable, round them to a consistent precision first to ensure each key is truly distinct and no data is silently merged. Normalize each key using round(value * 1000000.0) / 1000000.0 before passing to collect_by_key().

Upcoming (60 days notice from Sep 22, 2026)

Float division (/) will return decimals, not truncated integers.

Current behavior: The / operator on Float operands returns nearest integer. For example, 5.0 / 2 returns 2.0, not 2.5. If both operands are Int (for example, 5 / 2), the result returns 2.

Upcoming change (Nov 30, 2026): The float division on float operands will return with 16 decimal precision. After this date, 5.0 / 2.0 will return 2.5, 150.0 / 7.0 will return 21.428... instead of an integer value.

The precision of the result depends on how it is consumed: if the result type is Float, the value is computed up to 16 decimal digits of precision; if the result is coerced to a String it is formatted to 6 decimal digits instead.

For example, 5.0 / 2.0 will return 2.5, and 150.0 / 7.0 will return 21.4285714285714 as a Float, but 21.428571 if interpolated into a String.

Int / Int expressions such as 5 / 2 are unaffected and will continue to return 2.

To ensure integer results regardless of engine version, wrap float division in floor() or ceil():

  • floor(5.0 / 2.0) → always returns 2

  • ceil(5.0 / 2.0) → always returns 3

If your workflow intentionally expects decimal results from float division, no changes are needed. The upcoming division behavior from Nov 30,2026 will return decimal places also.

Note: 5/2 will still return 2 as the / operator is applied on integers.