{"record":{"id":"09d99d3cb162d72a","repo":"elsa-workflows/elsa-core","slug":"nohttpcontext-the-http-context-was-lost-during-workflow","errorCode":"NoHttpContext","errorMessage":"The HTTP context was lost during workflow execution. This typically occurs when a workflow initiated from an HTTP endpoint is suspended and later resumed in a different execution context (e.g., background processing, virtual actor, or after a workflow transition). The original HTTP request context that expects a response is no longer available.","messagePattern":"The HTTP context was lost during workflow execution\\. This typically occurs when a workflow initiated from an HTTP endpoint is suspended and later resumed in a different execution context \\(e\\.g\\., background processing, virtual actor, or after a workflow transition\\)\\. The original HTTP request context that expects a response is no longer available\\.","errorType":"error_code","errorClass":"FaultException","httpStatus":null,"severity":"error","filePath":"src/modules/Elsa.Http/Activities/WriteHttpResponse.cs","lineNumber":85,"sourceCode":"    /// <summary>\n    /// The headers to return along with the response.\n    /// </summary>\n    [Input(\n        Description = \"The headers to send along with the response.\",\n        UIHint = InputUIHints.JsonEditor,\n        Category = \"Advanced\"\n    )]\n    public Input<HttpHeaders?> ResponseHeaders { get; set; } = new(new HttpHeaders());\n\n    /// <inheritdoc />\n    protected override async ValueTask ExecuteAsync(ActivityExecutionContext context)\n    {\n        var httpContextAccessor = context.GetRequiredService<IHttpContextAccessor>();\n        var httpContext = httpContextAccessor.HttpContext;\n\n        if (httpContext == null)\n        {\n            throw new FaultException(\n                HttpFaultCodes.NoHttpContext, \n                HttpFaultCategories.Http, \n                DefaultFaultTypes.System, \n                \"The HTTP context was lost during workflow execution. This typically occurs when a workflow initiated from an HTTP endpoint is suspended and later resumed in a different execution context (e.g., background processing, virtual actor, or after a workflow transition). The original HTTP request context that expects a response is no longer available.\");\n        }\n\n        await WriteResponseAsync(context, httpContext.Response);\n    }\n\n    private async Task WriteResponseAsync(ActivityExecutionContext context, HttpResponse response)\n    {\n        // Set status code.\n        var statusCode = StatusCode.GetOrDefault(context, () => HttpStatusCode.OK);\n        response.StatusCode = (int)statusCode;\n\n        // Add headers.\n        var headers = context.GetHeaders(ResponseHeaders);\n        foreach (var header in headers)","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/elsa-workflows/elsa-core/blob/fe9217bdfa0e27f0e09e45006eb6898f616e513d/src/modules/Elsa.Http/Activities/WriteHttpResponse.cs#L67-L103","documentation":"WriteHttpResponse writes a response body/status to the ASP.NET HTTP context captured when the workflow's HTTP endpoint received the request. If IHttpContextAccessor.HttpContext is null during ExecuteAsync, the activity throws a FaultException with code NoHttpContext, because there is no live response to write. This guards against workflows resuming after suspension in a non-HTTP execution context.","triggerScenarios":"ExecuteAsync of WriteHttpResponse runs while httpContextAccessor.HttpContext is null — the workflow was suspended (bookmark, timer, task) after the HTTP request completed and resumed on a background worker, virtual actor, or different node without the original request context.","commonSituations":"HTTP-triggered workflow with an intermediate Delay or human-task approval, then attempting to send the final HTTP response; server restarts while the workflow was suspended; distributed deployments where the resuming instance never saw the original request.","solutions":["Write the HTTP response before any suspending activity; if asynchronous delivery is needed, respond with 202 Accepted early and push the final result via a callback/SignalR.","Refactor so the final response is produced by a subsequent HttpEndpoint request (the client polls or a webhook triggers the completion response).","Use workflow-correlated delivery mechanisms (e.g., HTTP bookmarks where the resume request itself carries the HTTP context) instead of assuming the original context survives."],"exampleFix":"// before: HttpEndpoint -> Event(approval) -> WriteHttpResponse(\"done\") // NoHttpContext on resume\n// after: HttpEndpoint -> WriteHttpResponse(\"pending\") -> Event(approval) -> notify via webhook/SignalR","handlingStrategy":"validation","validationCode":"// Guard before writing the response in the workflow\nvar hasHttpContext = httpContextAccessor.HttpContext is not null;\nif (!hasHttpContext)\n{\n    // fall back to non-HTTP delivery (store result, notify via SignalR/webhook)\n}","typeGuard":null,"tryCatchPattern":"// Inspect the fault after resume\nworkflowDispatcher.OnFault((instance, fault) => {\n    if (fault.Code == HttpFaultCodes.NoHttpContext)\n        logger.LogWarning(\"Workflow {Id} attempted HTTP response without context; switch to callback pattern\", instance.Id);\n});","preventionTips":["Write the HTTP response synchronously before any suspending activity.","Use 202 Accepted + out-of-band result delivery for long-running flows.","In distributed deployments, never assume the resuming node has the original request."],"tags":["http","workflow","suspension","aspnetcore"],"backgroundTag":"invalid-state-transition","analyzedSha":"fe9217bdfa0e27f0e09e45006eb6898f616e513d","analyzedAt":"2026-09-13T20:32:34.702Z","contentChangedAt":"2026-09-13T20:32:34.702Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}