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

  1. Always evaluate templates with a `LiquidTemplateContext` (obtained via ILiquidTemplateManager / the Liquid view engine), which carries the tenant service provider.
  2. In custom render code, build the context via `await _liquidTemplateManager...` APIs instead of instantiating Fluid contexts yourself.
  3. 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

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


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)