Skip to content

[JS/TS] Async.StartChild with a timeout doesn't cancel the child #5093

Closed

Description

@simontreanor

When the timeout passed to Async.StartChild expires on the JS target, the TimeoutException is raised as it should be, but the child computation carries on running to completion. On .NET the child is cancelled, and the Python target was changed to do the same in #5035. (#4481 fixed the opposite problem, where the timeout always fired, so this is the part that's left.)

Fable 5.21.0, Node 24.14.1.

Repro

module Repro

let mutable childFinished = false

let slow =
    async {
        do! Async.Sleep 300
        childFinished <- true
        return 42
    }

async {
    try
        let! child = Async.StartChild(slow, millisecondsTimeout = 100)
        let! _ = child
        ()
    with e ->
        printfn "timeout raised: %s" e.Message
    do! Async.Sleep 400
    printfn "child finished after timeout = %b" childFinished
}
|> Async.StartImmediate
.NET Fable 5.21 (JS)
TimeoutException after ~100ms yes yes
child finished after timeout false true

Cause

startChild in Async.ts starts the child on the parent's token and races it against a setTimeout; when the timeout wins the race rejects, but nothing cancels the child.

The existing test, "Async.StartChild applies timeout" in tests/Js/Main/AsyncTests.fs, can't catch this, because the child sleeps for 1,000ms but the test checks x straight after the 200ms timeout, before the child would have appended "X". Waiting past the child's sleep before the equal would catch it.

Possible fix

Start the child on its own token, linked to the parent's so that cancelling the parent still cancels the child, and cancel that token when the timeout fires.

Activity

  1. added a commit that references this issue on Oct 21, 2026
    8a1e179
  2. MangelMaxime commented on Oct 21, 2026

    @MangelMaxime
    Member

    Fixed by #5097, available in the next release.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions