{"record":{"id":"4199b1490ea35d84","repo":"OrchardCMS/OrchardCore","slug":"an-implementation-of-liquidtemplatecontext-is-required","errorCode":null,"errorMessage":"An implementation of 'LiquidTemplateContext' is required","messagePattern":"An implementation of 'LiquidTemplateContext' is required","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/OrchardCore/OrchardCore.DisplayManagement.Liquid/Values/CultureValue.cs","lineNumber":77,"sourceCode":"    public override ValueTask<FluidValue> GetValueAsync(string name, TemplateContext context)\n    {\n        return name switch\n        {\n            nameof(CultureInfo.Name) => ValueTask.FromResult<FluidValue>(new StringValue(Culture.Name)),\n            nameof(CultureInfo.NativeName) => ValueTask.FromResult<FluidValue>(new StringValue(Culture.NativeName)),\n            nameof(CultureInfo.DisplayName) => ValueTask.FromResult<FluidValue>(new StringValue(Culture.DisplayName)),\n            nameof(CultureInfo.TwoLetterISOLanguageName) => ValueTask.FromResult<FluidValue>(new StringValue(Culture.TwoLetterISOLanguageName)),\n            \"Dir\" => ValueTask.FromResult<FluidValue>(new StringValue(Culture.GetLanguageDirection())),\n            \"SupportedCultures\" => _culture is null ? GetSupportedCulturesAsync(context) : ValueTask.FromResult<FluidValue>(NilValue.Instance),\n            \"DefaultCulture\" => _culture is null ? GetDefaultCultureAsync(context) : ValueTask.FromResult<FluidValue>(NilValue.Instance),\n            _ => ValueTask.FromResult<FluidValue>(NilValue.Instance)\n        };\n    }\n\n    private static async ValueTask<FluidValue> GetSupportedCulturesAsync(TemplateContext context)\n    {\n        var ctx = context as LiquidTemplateContext\n            ?? throw new InvalidOperationException($\"An implementation of '{nameof(LiquidTemplateContext)}' is required\");\n\n        var services = ctx.Services;\n        var localizationService = services.GetRequiredService<ILocalizationService>();\n        var supportedCultures = await localizationService.GetSupportedCulturesAsync();\n\n        return new ArrayValue(supportedCultures.Select(c => new CultureValue(CultureInfo.GetCultureInfo(c))).ToArray());\n    }\n\n    private static async ValueTask<FluidValue> GetDefaultCultureAsync(TemplateContext context)\n    {\n        var ctx = context as LiquidTemplateContext\n            ?? throw new InvalidOperationException($\"An implementation of '{nameof(LiquidTemplateContext)}' is required\");\n\n        var services = ctx.Services;\n        var localizationService = services.GetRequiredService<ILocalizationService>();\n\n        return new CultureValue(CultureInfo.GetCultureInfo(await localizationService.GetDefaultCultureAsync()));\n    }","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/OrchardCMS/OrchardCore/blob/4306c0717fe573f6fca1b4955909ddab6a192807/src/OrchardCore/OrchardCore.DisplayManagement.Liquid/Values/CultureValue.cs#L59-L95","documentation":"The `cultures` Liquid value (CultureValue.GetSupportedCulturesAsync) requires the Liquid variable's TemplateContext to be Orchard Core's LiquidTemplateContext, because it needs `Services` (the tenant's IServiceProvider) to resolve ILocalizationService. When the context passed at evaluation time is a plain FluidCoreTemplateContext/TemplateContext, the cast fails and this InvalidOperationException is thrown.","triggerScenarios":"Evaluating `{{ cultures }}` (or another CultureValue member) with a raw Fluid `TemplateContext` instead of `LiquidTemplateContext` — e.g. custom code rendering Liquid templates manually, or invoking the member from a non-Liquid host.","commonSituations":"Unit tests or custom render pipelines that construct `new TemplateContext()` directly; embedding Fluid outside Orchard's Liquid view engine; calling template members from background services without the scoped Liquid context.","solutions":["Always evaluate templates with a `LiquidTemplateContext` (obtained via ILiquidTemplateManager / the Liquid view engine), which carries the tenant service provider.","In custom render code, build the context via `await _liquidTemplateManager...` APIs instead of instantiating Fluid contexts yourself.","If you must use a plain context, do not reference Orchard-provided Liquid values like `cultures`."],"exampleFix":"// before\nvar context = new TemplateContext();\nvar result = await template.RenderAsync(context);\n// after\nvar context = new LiquidTemplateContext(sp, _memberAccessor) { Model = model };\nvar result = await template.RenderAsync(context);","handlingStrategy":"type-guard","validationCode":"if (context is not LiquidTemplateContext) throw new InvalidOperationException(\"cultures requires a LiquidTemplateContext with tenant services\");","typeGuard":"bool IsLiquidContext(TemplateContext ctx) => ctx is LiquidTemplateContext;","tryCatchPattern":"try { return await template.RenderAsync(ctx); } catch (InvalidOperationException ex) when (ex.Message.Contains(\"LiquidTemplateContext\")) { /* switch to LiquidTemplateContext and retry */ }","preventionTips":["Never construct raw Fluid TemplateContext for Orchard templates; use ILiquidTemplateManager.","Centralize template rendering in one helper that always creates LiquidTemplateContext.","In tests, mimic the Liquid view engine's context construction."],"tags":["liquid","fluid","type-cast","orchardcore"],"backgroundTag":"type-mismatch","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"}