{"record":{"id":"34dec29bf8f1ab8c","repo":"OrchardCMS/OrchardCore","slug":"buffer-has-already-been-rendered","errorCode":null,"errorMessage":"Buffer has already been rendered","messagePattern":"Buffer has already been rendered","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/OrchardCore/OrchardCore.DisplayManagement.Liquid/ViewBufferTextWriterContent.cs","lineNumber":212,"sourceCode":"    public override void Write(StringBuilder value)\n    {\n        if (value != null)\n        {\n            foreach (var chunk in value.GetChunks())\n            {\n                if (!chunk.IsEmpty)\n                {\n                    Write(chunk.Span);\n                }\n            }\n        }\n    }\n\n    public void WriteTo(TextWriter writer, HtmlEncoder encoder)\n    {\n        if (_builder == null)\n        {\n            throw new InvalidOperationException(\"Buffer has already been rendered\");\n        }\n\n        if (_previousPooledBuilders != null)\n        {\n            foreach (var pooledBuilder in _previousPooledBuilders)\n            {\n                foreach (var chunk in pooledBuilder.Builder.GetChunks())\n                {\n                    if (!chunk.IsEmpty)\n                    {\n                        writer.Write(chunk.Span);\n                    }\n                }\n            }\n        }\n\n        foreach (var chunk in _builder.GetChunks())\n        {","sourceCodeStart":194,"sourceCodeEnd":230,"githubUrl":"https://github.com/OrchardCMS/OrchardCore/blob/4306c0717fe573f6fca1b4955909ddab6a192807/src/OrchardCore/OrchardCore.DisplayManagement.Liquid/ViewBufferTextWriterContent.cs#L194-L230","documentation":"ViewBufferTextWriterContent wraps pooled ViewBufferTextWriter builders. Once the content has been written to a final TextWriter (rendered), the internal builder is released back to the pool and set to null. Writing or serializing the same content again is invalid, so WriteTo throws to prevent use-after-return of pooled memory.","triggerScenarios":"Calling WriteTo(writer, encoder) — typically from HtmlString/serialization code — on a ViewBufferTextWriterContent instance that was already rendered once; re-rendering a cached liquid shape/tagBuilder output; holding onto the IHtmlContent produced by a Liquid expression and re-emitting it.","commonSituations":"Caching an IHtmlContent result (e.g. in a dictionary or memoized tag helper) and writing it twice; double-rendering the same shape in a layout and a partial; async races where a render is attempted while/after the buffer was flushed.","solutions":["Render the content once per output writer; re-execute the Liquid template or shape for each additional output","If caching is needed, cache the rendered string (e.g. stringWriter output) rather than the IHtmlContent buffer","Check for code paths that serialize content more than once (logging + response writing) and remove the duplicate"],"exampleFix":"// before\n_htmlContentCache[key] = liquidResult; // rendered once later twice\n// after\n_htmlContentCache[key] = htmlEncoder.Encode-free string rendered via StringWriter;\nvar sw = new StringWriter();\nliquidResult.WriteTo(sw, HtmlEncoder.Default);\n_htmlContentCache[key] = sw.ToString();","handlingStrategy":"try-catch","validationCode":"bool canWrite = content is ViewBufferTextWriterContent v && v.ToString() != null; // prefer avoiding re-use entirely: cache strings instead of buffers","typeGuard":"bool IsRenderedOnce(IHtmlContent c) => c is ViewBufferTextWriterContent vbc && vbc.GetType().GetProperty(\"_builder\", BindingFlags.NonPublic | BindingFlags.Instance) == null;","tryCatchPattern":"try { content.WriteTo(writer, encoder); } catch (InvalidOperationException ex) when (ex.Message == \"Buffer has already been rendered\") { // re-render instead of reusing _logger.LogWarning(\"Buffer re-use detected; re-rendering\"); content = await RenderFreshAsync(); content.WriteTo(writer, encoder); }","preventionTips":["Never cache IHtmlContent from Liquid/shape rendering — cache rendered strings","Render each shape exactly once per request","Watch for double writes (log + response) of the same shape instance"],"tags":["liquid","razor","buffering","pooled-memory","aspnetcore"],"backgroundTag":"invalid-state-transition","analyzedSha":"4306c0717fe573f6fca1b4955909ddab6a192807","analyzedAt":"2026-09-13T17:41:05.024Z","contentChangedAt":"2026-09-13T17:41:05.024Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}