{"record":{"id":"e931c2060e1ee413","repo":"dotnet/reactive","slug":"did-not-get-error-output-from-program","errorCode":null,"errorMessage":"Did not get error output from program","messagePattern":"Did not get error output from program","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"Rx.NET/Test/Gauntlet/Checks/TransitiveReferences/CheckTransitiveFrameworkReference/RunTransitiveFrameworkReferenceCheck.cs","lineNumber":287,"sourceCode":"                    if (!stdOutTask.IsCompleted)\n                    {\n                        // The process finished, but the standard output task is still running. It's possible that\n                        // it is nearly done, so give it some time.\n                        await Task.WhenAny(stdOutTask, Task.Delay(2000));\n                    }\n                    if (!stdErrTask.IsCompleted)\n                    {\n                        await Task.WhenAny(stdErrTask, Task.Delay(2000));\n                    }\n\n                    if (!stdOutTask.IsCompleted)\n                    {\n                        throw new InvalidOperationException(\"Did not get output from program\");\n                    }\n\n                    if (!stdErrTask.IsCompleted)\n                    {\n                        throw new InvalidOperationException(\"Did not get error output from program\");\n                    }\n                    runStdOut = await stdOutTask;\n                    runStdErr = await stdErrTask;\n\n                    await processTask;\n                    runExitCode = process.ExitCode;\n                }\n#pragma warning restore IDE0063 // Use simple 'using' statement\n            }\n            else\n            {\n                //Debugger.Break();\n                Console.WriteLine(r.BuildStdOut);\n            }\n            return new(r.BuildProcessExitCode, r.OutputFolder, r.BuildStdOut, runExitCode, runStdOut, runStdErr);\n        }\n\n        // TODO: we will actually build two apps: before and after upgrade.","sourceCodeStart":269,"sourceCodeEnd":305,"githubUrl":"https://github.com/dotnet/reactive/blob/94b5d5ab912789f5abe9a72138a25bbd716fe59c/Rx.NET/Test/Gauntlet/Checks/TransitiveReferences/CheckTransitiveFrameworkReference/RunTransitiveFrameworkReferenceCheck.cs#L269-L305","documentation":"Companion check to the stdout timeout: after confirming stdout completed, RunScenarioAsync verifies the stderr task completed; if not it throws InvalidOperationException('Did not get error output from program'). The child process closed stdout but never finished writing/closing stderr, indicating a partial hang or abnormal termination.","triggerScenarios":"stdOutTask completed but stdErrTask did not when the polling loop ended — the process finished standard output but stderr stayed open, e.g., a background thread still holding the error stream or the process hung after writing output.","commonSituations":"Child process spawns a lingering child/thread that keeps stderr open; process killed mid-write to stderr; pipe deadlock where stderr buffer filled while only stdout was being read.","solutions":["Check whether the app leaves background processes/threads alive that hold stderr open","Ensure the harness reads stdout and stderr concurrently to avoid pipe-buffer deadlock","Inspect stderr content after the run for crash traces explaining the partial termination","Increase the wait timeout or add explicit process kill + stream close on timeout"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// verify the app terminates cleanly and closes both streams\np.WaitForExit(timeoutMs);\nif (!p.HasExited) { p.Kill(entireProcessTree: true); throw new InvalidOperationException(\"App left stderr open; killed\"); }","typeGuard":null,"tryCatchPattern":"try\n{\n    await check.RunScenarioAsync(...);\n}\ncatch (InvalidOperationException ex) when (ex.Message == \"Did not get error output from program\")\n{\n    // investigate lingering child processes / threads holding stderr\n}","preventionTips":["Kill the entire process tree on timeout so no child keeps streams open","Avoid background threads writing to Console in the test app","Always read stdout and stderr in parallel","Treat unterminated streams as a hang signal and dump diagnostics"],"tags":["process","timeout","stderr","test-harness"],"backgroundTag":"request-timeout","analyzedSha":"94b5d5ab912789f5abe9a72138a25bbd716fe59c","analyzedAt":"2026-09-15T02:26:24.759Z","contentChangedAt":"2026-09-15T02:26:24.759Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}