{"record":{"id":"9e695547febd39e1","repo":"karatelabs/karate","slug":"error-flushing-output-writer","errorCode":null,"errorMessage":"error flushing output writer","messagePattern":"error flushing output writer","errorType":"exception","errorClass":"TemplateOutputException","httpStatus":null,"severity":"error","filePath":"karate-core/src/main/java/io/karatelabs/markup/Markup.java","lineNumber":106,"sourceCode":"        Writer stringWriter = new FastStringWriter(100);\n        process(isPath, content, context, stringWriter);\n        return stringWriter.toString();\n    }\n\n    private void process(boolean isPath, String content, IContext context, Writer writer) {\n        try {\n            // Reset resolver state so processString can be called multiple times\n            if (templateResolver != null) {\n                templateResolver.resetStringTemplateState();\n            }\n            // the empty map (which becomes null) is used to signal an inline string template for HtmlTemplateResolver to handle\n            TemplateSpec templateSpec = new TemplateSpec(content, isPath ? Collections.emptyMap() : IS_STRING);\n            TemplateManager templateManager = wrapped.getConfiguration().getTemplateManager();\n            templateManager.parseAndProcess(templateSpec, context, writer);\n            try {\n                writer.flush();\n            } catch (IOException e) {\n                throw new TemplateOutputException(\"error flushing output writer\", content, -1, -1, e);\n            }\n        } catch (ResourceNotFoundException e) {\n            throw e; // Let 404s bubble up without logging\n        } catch (Exception e) {\n            if (hasFlowControlSignal(e)) {\n                // intentional control flow (e.g. context.redirect, context.switch) — not an error\n                throw new RuntimeException(e);\n            }\n            String formatted = logTemplateError(isPath, content, e);\n            // Carry the formatted block as the wrapper's message so callers\n            // (e.g. ServerRequestCycle.handleError) can surface it in the\n            // response body when in devMode without re-deriving line/col/source.\n            throw new RuntimeException(formatted, e);\n        }\n    }\n\n    private static boolean hasFlowControlSignal(Throwable e) {\n        Throwable t = e;","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/karatelabs/karate/blob/a22eb90246d958d15a47bf436693d0121ad2812d/karate-core/src/main/java/io/karatelabs/markup/Markup.java#L88-L124","documentation":"After Thymeleaf finishes parsing and processing a template into a writer, Markup.process flushes that writer. If flush() throws an IOException, it is wrapped in a TemplateOutputException with the message \"error flushing output writer\" and the template content as context. This indicates the underlying output sink (a backing file, socket, or response stream) failed while being flushed, not a problem with the template itself.","triggerScenarios":"Calling Markup.process(...) where the TemplateManager writes to a writer backed by a stream that fails on flush — e.g. a closed response stream, a full/broken pipe to a client, or a disk-backed writer that hit an I/O failure.","commonSituations":"Client disconnected mid-response when rendering HTML for an HTTP response; servlet output stream already committed/closed before flush; container shutdown or connection reset during template rendering; underlying file system errors for file-backed writers.","solutions":["Check the cause (`TemplateOutputException.getCause()` IOException) to identify the actual failing stream.","For HTTP responses, guard against writing after the response is committed or the client has disconnected before invoking Markup.process.","Retry the render if the failure was transient (e.g. a reset connection); for persistent stream errors, fix the writer lifecycle so it is open and writable.","Verify disk space and file permissions if the writer is file-backed."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Before rendering, ensure the target writer is open and writable\nif (!response.isCommitted() && writer != null) {\n    render(template, writer);\n}","typeGuard":null,"tryCatchPattern":"try {\n    markup.process(...);\n} catch (TemplateOutputException e) {\n    if (\"error flushing output writer\".equals(e.getMessage()) && e.getCause() instanceof IOException io) {\n        log.warn(\"Stream flush failed (client gone? disk full?): {}\", io.getMessage());\n        return; // often safe to swallow for aborted client connections\n    }\n    throw e;\n}","preventionTips":["Don't render into a response stream that is already committed or closed","Handle client-disconnect IOExceptions as benign for HTML responses","Monitor disk space for file-backed writers","Keep the template-independent cause chain for diagnosis"],"tags":["io","template","stream","flush"],"backgroundTag":"file-write-failed","analyzedSha":"a22eb90246d958d15a47bf436693d0121ad2812d","analyzedAt":"2026-09-12T09:01:00.220Z","contentChangedAt":"2026-09-12T09:01:00.220Z","schemaVersion":2},"datasetVersion":"2026-09-16T19:17:19.609Z"}