OrchardCMS/OrchardCore · error · InvalidOperationException
An implementation of 'LiquidTemplateContext' is required
Error message
An implementation of 'LiquidTemplateContext' is required
What it means
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.
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`.
Example fix
// before
var context = new TemplateContext();
var result = await template.RenderAsync(context);
// after
var context = new LiquidTemplateContext(sp, _memberAccessor) { Model = model };
var result = await template.RenderAsync(context); Defensive patterns
Strategy: type-guard
Validate before calling
if (context is not LiquidTemplateContext) throw new InvalidOperationException("cultures requires a LiquidTemplateContext with tenant services"); Type guard
bool IsLiquidContext(TemplateContext ctx) => ctx is LiquidTemplateContext;
Try / catch
try { return await template.RenderAsync(ctx); } catch (InvalidOperationException ex) when (ex.Message.Contains("LiquidTemplateContext")) { /* switch to LiquidTemplateContext and retry */ } Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- An implementation of 'LiquidTemplateContext' is required
- An implementation of 'LiquidTemplateContext' is required
- An implementation of 'LiquidTemplateContext' is required
- Cannot override href with other properties
- Format of the link cannot be determined based on the…
AI-assisted analysis of OrchardCMS/OrchardCore@4306c0717f (2026-09-13).
Data as JSON: /api/errors/4199b1490ea35d84.
Report an issue: GitHub.
Appendix: source
Thrown at src/OrchardCore/OrchardCore.DisplayManagement.Liquid/Values/CultureValue.cs:77
public override ValueTask<FluidValue> GetValueAsync(string name, TemplateContext context)
{
return name switch
{
nameof(CultureInfo.Name) => ValueTask.FromResult<FluidValue>(new StringValue(Culture.Name)),
nameof(CultureInfo.NativeName) => ValueTask.FromResult<FluidValue>(new StringValue(Culture.NativeName)),
nameof(CultureInfo.DisplayName) => ValueTask.FromResult<FluidValue>(new StringValue(Culture.DisplayName)),
nameof(CultureInfo.TwoLetterISOLanguageName) => ValueTask.FromResult<FluidValue>(new StringValue(Culture.TwoLetterISOLanguageName)),
"Dir" => ValueTask.FromResult<FluidValue>(new StringValue(Culture.GetLanguageDirection())),
"SupportedCultures" => _culture is null ? GetSupportedCulturesAsync(context) : ValueTask.FromResult<FluidValue>(NilValue.Instance),
"DefaultCulture" => _culture is null ? GetDefaultCultureAsync(context) : ValueTask.FromResult<FluidValue>(NilValue.Instance),
_ => ValueTask.FromResult<FluidValue>(NilValue.Instance)
};
}
private static async ValueTask<FluidValue> GetSupportedCulturesAsync(TemplateContext context)
{
var ctx = context as LiquidTemplateContext
?? throw new InvalidOperationException($"An implementation of '{nameof(LiquidTemplateContext)}' is required");
var services = ctx.Services;
var localizationService = services.GetRequiredService<ILocalizationService>();
var supportedCultures = await localizationService.GetSupportedCulturesAsync();
return new ArrayValue(supportedCultures.Select(c => new CultureValue(CultureInfo.GetCultureInfo(c))).ToArray());
}
private static async ValueTask<FluidValue> GetDefaultCultureAsync(TemplateContext context)
{
var ctx = context as LiquidTemplateContext
?? throw new InvalidOperationException($"An implementation of '{nameof(LiquidTemplateContext)}' is required");
var services = ctx.Services;
var localizationService = services.GetRequiredService<ILocalizationService>();
return new CultureValue(CultureInfo.GetCultureInfo(await localizationService.GetDefaultCultureAsync()));
}View on GitHub (pinned to 4306c0717f)