Skip to main content
Known Participant
June 22, 2026
Question

Command-line builds freezing intermittently: "Error" pop-up / hang during batch compilation — how do you keep it from happening?

  • June 22, 2026
  • 1 reply
  • 7 views

The context

I generate my online help (frameless output, EN/FR projects) through scripted, unattended command-line builds rather than launching them by hand from the RoboHelp UI. For a long time these builds were frustratingly unreliable: I had a failure rate of roughly 20%, with no genuinely detectable explanation. A compilation would sometimes throw an "Error" pop-up, hang, or simply abort, and there was no clear pattern — same project, same machine, different outcome.

These were not just cosmetic false alarms: a real share of the runs genuinely froze and produced nothing usable. Worse, the failure rate tended to climb the more I compiled — the more builds I chained in a session, the more likely the next one was to wedge.

For reference, I'm currently on the 2026 release, but everything below also applies to the 2022 version — I've reproduced both the problem and the fix on it.

What I tried

Before finding the cause I ran a lot of tests — different command-line invocations, different ways of starting the process, repeated runs to see whether the failure was random. The behavior was maddeningly inconsistent.

To get to the bottom of it, I went fairly low-level and built a small watchdog that "sniffs" the build at the executable level. For every compilation it:

  • enumerates the RoboHelp .exe processes actually spawned (and their child processes),
  • tracks their lifetime and exit codes,
  • samples their CPU activity at regular intervals, and
  • watches what they write to their output streams and when.

The key signal turned out to be CPU: a healthy build keeps consuming CPU until it finishes; a wedged one stops using CPU entirely while the process stays alive. So the watchdog flags a build as hung when CPU activity stays flat for a defined idle window, kills the leftover RoboHelp processes, and relaunches.

One important practical note: the timeout / idle-window values are not universal. The right thresholds depend on the OS, the machine, the available RAM and disk speed — a fast workstation finishes a module in ~20 s, a slower or busier one legitimately takes several times longer, and you don't want the watchdog to kill a build that is simply slow. I had to tune these values empirically for my environment, and anyone reusing the idea should expect to do the same.

What was actually going wrong

The root cause had nothing to do with the project content or the build itself — it was the output stream.

When RoboHelp runs from the command line, its executables write to their standard output and standard error (stdout/stderr). Those streams are connected through an OS pipe, and a pipe has a small, fixed buffer — on the order of a few tens of kilobytes (in my case the process would wedge once it had produced roughly 50–64 KB of output with nothing reading it).

Here's the mechanism: if the launching process does not continuously read that pipe, the buffer fills up. Once it's full, the next write from RoboHelp blocks — the OS suspends the writing thread until someone drains the pipe. Nobody ever does, so the process sits there forever, CPU at zero, "alive" but frozen. That's a textbook broken-pipe / blocked-pipe (EPIPE) situation.

The proper name for this condition is a broken pipe, whose standard error code is EPIPE ("broken pipe"): a process tries to write to a pipe that can no longer accept data, and the write either blocks or fails. The underlying cause is exactly that — an output pipe that nobody is draining.

This also explains the two things that puzzled me for months:

  • Why it looked random — it's purely a function of how much a given module writes to its streams. A small module finishes before the buffer fills; a chatty one crosses the threshold and wedges. Same command, different output volume, different outcome.
  • Why "the more I compile, the worse it gets" — chaining builds in one session means more accumulated output and more processes competing, so the buffer crosses its limit more often.

The fix

The fix was simply to launch each build with its output redirected and actively drained — i.e. attach a reader that continuously consumes stdout/stderr for the entire life of the process, so the pipe buffer can never fill. (Draining has to happen live, during the build; there's nothing to "flush" beforehand, because the pipe only exists once the process is launched.) On top of that I kept the CPU watchdog as a safety net, with an automatic relaunch.

Since putting this in place, the "Error" pop-up / hang has disappeared entirely — I have not seen it once since the discovery.

Real numbers from a recent run

A typical batch of 28 module compilations:

  • 28 / 28 succeeded → 100% eventual success.
  • 24 succeeded on the first attempt (~86%); the other 4 hit the old freeze and were automatically recovered on the second attempt.
  • 0 final failures, no manual intervention.

So even on a run where the legacy freeze still tried to bite a few times, the drain-the-stream approach plus an automatic retry brought the real-world failure rate to zero.

Why the Adobe-provided files worked, and why my solution is language-agnostic

This also explains why the files Adobe made available to work around the problem behaved better. It wasn't really a built-in "mechanism" — more a set of files provided as a workaround — but the reason it helped was exactly this: that path already consumes the output stream properly, so the pipe never backs up. The pop-up was a symptom of my environment not draining the stream, not of a RoboHelp defect.

The nice consequence is that the solution is not tied to any particular scripting language. I happen to use PowerShell, but the principle — redirect the child process's output and keep reading it until the process exits — can be implemented in any language or shell (batch, Python, Node, etc.). It's a general rule for spawning RoboHelp (or any chatty console process) unattended.

A minimal PowerShell example

This is the bare-bones pattern, stripped down to the essentials. The two things that matter: start the process with its output redirected, and attach an asynchronous reader so the pipe is drained continuously while the build runs. The CPU watchdog is the safety net on top.

 

# --- launch with stdout/stderr redirected ---

$psi = [System.Diagnostics.ProcessStartInfo]::new()

$psi.FileName = $roboHelpExe # the RoboHelp CLI executable

$psi.Arguments = $buildArguments # your project / output args

$psi.UseShellExecute = $false # required to redirect

$psi.RedirectStandardOutput = $true

$psi.RedirectStandardError = $true

$psi.CreateNoWindow = $true

$proc = [System.Diagnostics.Process]::new()

$proc.StartInfo = $psi

# --- drain BOTH streams continuously (this is the whole point) ---

# Without these handlers the pipe buffer fills (~50-64 KB) and RoboHelp blocks.

$proc.add_OutputDataReceived({ param($s,$e) if ($e.Data) { } }) # read & discard, or log $e.Data

$proc.add_ErrorDataReceived( { param($s,$e) if ($e.Data) { } })

[void]$proc.Start()

$proc.BeginOutputReadLine() # start the async readers immediately

$proc.BeginErrorReadLine()

# --- CPU watchdog: kill + relaunch if the process goes idle ---

# IdleLimit must be tuned to your hardware (OS / CPU / RAM / disk).

$idleLimitSec = 90

$lastCpu = 0.0

$idleSec = 0

while (-not $proc.HasExited) {

Start-Sleep -Seconds 3

$proc.Refresh()

$cpu = $proc.TotalProcessorTime.TotalSeconds

if ($cpu - $lastCpu -lt 0.1) { $idleSec += 3 } else { $idleSec = 0 }

$lastCpu = $cpu

if ($idleSec -ge $idleLimitSec) {

# hung (the old "Error" pop-up / EPIPE case) -> kill the whole tree and retry

$proc.Kill($true)

break

}

}

Wrap that in a retry loop (e.g. up to 4 attempts) and you get the behavior shown in the log above: the rare stall is killed and relaunched automatically, and the batch finishes with a real-world failure rate of zero. The exact same approach works unchanged whether you script it in PowerShell, Python, Node, or plain batch — only the redirect/drain API differs.

Takeaway

If you automate RoboHelp builds from the command line and you see intermittent "Error" pop-ups, hangs, or real failures — especially failures that get more frequent the more you compile — check that whatever launches the build is continuously reading the process's stdout/stderr. Don't let the pipe buffer fill. A CPU-based watchdog with an automatic relaunch (tuned to your hardware) makes it bulletproof.

Happy to share more detail if it's helpful — and again, apologies if this was already covered somewhere.

Thanks!

 

    1 reply

    Peter Grainge
    Community Expert
    Community Expert
    June 22, 2026

    This is probably beyond most of the regular supporters, certainly beyond me. If no one responds, the only option is Adobe Support. See https://helpx.adobe.com/contact/enterprise-support.other.html#robohelp for your Adobe Support options. The email link tcssup@adobe.com is recommended as it reaches a team dedicated to Technical Communication Suite products including RoboHelp.

    When you contact them, do include the version of RoboHelp.


    My site www.grainge.org includes many free Authoring and RoboHelp resources that may be of help.

     

    Use the menu (bottom right) to mark the Best Answer or Highlight particularly useful replies. Found the answer elsewhere? Share it here.
    Known Participant
    June 22, 2026

    Hi Peter, thanks for the reply. It was more of an experience share — describing the problem and providing the solution. I wasn't sure where else to post it.

    There's no question in my post, just a universal and tried-and-true fix for anyone who has (inevitably) run into this issue.
    Have a nice day.