Diagnostics
- BCF1001
- BCF1002
- BCF1003
- BCF1004
- BCF1005
- BCF2001
- BCF3029
- BCF3030
- BCF3001
- BCF3015
- BCF3009
- BCF1006
- BCF3016
- BCF3027
- BCF3008
- BCF3026
- BCF3010
- BCF3011
- BCF3023
- BCF3024
- BCF3033
- BCF3034
- BCF3039
- BCF3040
- BCF3019
- BCF3028
- BCF3035
- BCF3036
- BCF3038
- BCF3002
- BCF3003
- BCF3004
- BCF2002
- BCF3032
- BCF3043
- BCF3044
- BCF3005
- BCF3006
- BCF3007
- BCF3012
- BCF3013
- BCF3014
- BCF3022
- BCF3025
- BCF3042
- BCF3017
- BCF3018
- BCF3020
- BCF3031
- BCF3041
Every diagnostic this compiler reports, what it means, and what to write instead.
The build prints the ID. Search this page for it.
Your class and its getter#
BCF1001#
Error. The class declaring Body or Chrome is not partial, so there is nowhere to emit the
generated RenderView.
public class Home : BodyComponentBase // BCF1001 public partial class Home : BodyComponentBase // what to write instead
Only the class that declares the override needs the modifier. A class that merely inherits a BlazorCodeFirst base without declaring one has nothing generated into it: an intermediate abstract base, a leaf whose base already declares the override, and a re-abstraction are all left alone.
Without this diagnostic the missing modifier would surface as CS0534 against the abstract
RenderView, which names the missing member and never the modifier.
BCF1002#
Error. The expression names something the generated file cannot see, or a [ViewPart] method does
not satisfy the static-expansion contract.
protected override View Body => Div.Attr("data-found", _rows.TryGetValue(_key, out var row)) .Attr("title", row.Name); // BCF1002: 'row' cannot exist there
The generator does not emit an element's parts in the order you wrote them, so a local declared in one part of the expression does not reach a reference in another. Declare it in a statement ahead of the return instead.
Two positions do carry a declaration across, because each becomes a header in the generated code
that encloses whatever reads it: an If condition scopes over both branches, and a ForEach source
over the content and the key.
This is what separates BCF1002 from BCF1003. BCF1003 means the expression could not be sequenced; BCF1002 means it could, and named something the generated file cannot see.
A [ViewPart] body follows the same reserved-name rule BCF1004 states for its getter.
BCF1003#
Error. The expression reached the model stage and could not be translated, because it uses a construct the generator does not analyze.
Div[_kids] // BCF1003: a child list passed whole Div[new View[] { … }] // BCF1003: an explicit array Div[[..items]] // BCF1003: a spread
Use ForEach for repetition. Everything the generator reads is listed in
elements and decorations and control flow:
element helpers, Component<T>(), Fragment, Raw, an inline expression lambda, and a call to a
method marked [ViewPart].
Marking a View-returning method of your own [ViewPart] keeps the factoring rather than inlining
its markup back into the caller.
A spliced projection (.. source.Select(item => …)) carries its body across under the author's own
names, the same way BCF1004's getter does, so BCF1004's reserved-name rule reaches it too.
BCF1004#
Error. The getter does not reach a single returned expression.
protected override View Body => Div[H1["Hello"]]; // fine protected override View Body { get => Div[H1["Hello"]]; } // fine protected override View Body { get { return Div[H1["Hello"]]; } } // fine protected override View Body { get; } = default; // BCF1004
Locals and expression statements may precede that return. They are copied into the generated
RenderView ahead of the calls that emit render-tree frames:
protected override View Body { get { var greeting = $"Hello, {_name}"; return Div[H1[greeting]]; } }
A second return needs a sequence space of its own, so it is not accepted, and neither is an auto
property, which declares no getter body at all. A native if/else or switch may end the getter
instead — see BCF2002 — but a native foreach cannot: a property getter cannot be a C#
iterator block, so yield return is invalid there no matter what this diagnostic says. The
equivalent shape is accepted only on a [ViewPart] method, as an iterator (see
control flow), since a method, unlike a getter, can be
one. A local declared __builder or prefixed __bcf_ cannot be declared here either: the generator
reserves both spellings everywhere a transplanted local can land. Rename the local. If the body
genuinely cannot be written in this shape, override RenderView by hand: the design-time expression
is then unused, and nothing is reported.
BCF1004 reports the declaration, which is what separates it from BCF1003. A class can carry a
missing partial and an untranslatable getter at once, and only one is reported at a time: BCF1001
runs first, and adding the modifier is what surfaces BCF1004.
BCF1005#
Error. A nested class declares a design-time expression.
public partial class Page { public partial class Row : BodyComponentBase // BCF1005 { } }
Move the component to a top-level type. Reopening a nested class from the generated file would mean re-declaring every enclosing type, its type parameters included, so a nested component is rejected rather than half emitted. Without the diagnostic it would surface as CS0534, which names the missing member and never the nesting.
Where the surface is read#
BCF2001#
Info. The call cannot be expanded statically, so this area renders through a runtime fragment and loses its static diff optimization.
The generator expands what it can read: the design-time surface, and [ViewPart] methods declared
in this compilation. A call it cannot read is correct and renders correctly. Its frames are rebuilt
rather than diffed against a static template.
A [ViewPart] in a referenced project or a NuGet package reaches this, because the generator
collects definitions from the current compilation's syntax and IL carries no body. Reuse across an
assembly boundary belongs in a component.
BCF3029#
Error. Design-time syntax is written where nothing reads it, so it renders nothing and wires up no handler.
private void OnSomething() { // BCF3029: renders nothing, and DoThing is never called var card = Div.Class("card").OnClick(DoThing)[Span["hello"]]; }
Html.Div, .Class(...), .OnClick(...) and every other factory and decoration are inert. View
is an empty struct, an element helper returns nothing, and a decoration returns its receiver
unchanged. The generator reads the syntax you wrote, never the value, and it reads it in three
places: a component's Body, a layout's Chrome, and the body of a [ViewPart] method.
The same API is callable from anywhere, and nothing reads it outside those three places. It compiles, but it emits no render-tree frames, so nothing is rendered and no event handler is registered.
Caching a value into a field or property of a design-time type is left alone. Only a local, a discard, or an argument is reported.
BCF3030#
Error. The call reaches a View-returning method that builds from the design-time surface but
carries no [ViewPart], so it renders nothing.
private static View Card(string title) => Div.Class("card")[H2[title]]; protected override View Body => Div[Card("Hello")]; // BCF3030
Mark the method [ViewPart] if it is static, or make it a component. Without the attribute the
method's result carries no fragment, so the call emits no frames.
This is BCF3029 seen from the other side of the call. BCF3029 reports design-time syntax written where nothing reads it; this reports a call whose callee wrote design-time syntax that nothing read.
BCF3001#
Error. State is mutated inside the design-time expression.
protected override View Body { get { _renderCount++; // BCF3001 return Div[Span[$"{_renderCount}"]]; } }
private void OnShown() => _renderCount++; // what to write instead protected override View Body => Div[Span[$"{_renderCount}"]];
The getter is a projection of state to UI, and it is translated rather than run. Move the mutation to an event handler.
Statements ahead of the return are translated too, so a mutation written in one of them is BCF3001 as it always was.
BCF3015#
Error. A type name in a design-time value expression could not be resolved and its spelling depends on the source file's lexical context.
Values are copied into a generated file that has no using directives. Resolved type names are
rewritten as global::-qualified names; an unresolved context-dependent one cannot be normalized
safely.
Fix the name, fully qualify it, move a source-generated type to a referenced project, or replace it
with a hand-written C# type. A reference already rooted at global:: is preserved and left to
ordinary C# resolution. Generic type arguments are checked independently.
Elements#
BCF3009#
Error. The Element tag is not a compile-time constant string spelled like a tag name.
private const string Widget = "my-widget"; Element(Widget) // fine Element(_kind + "-widget") // BCF3009: not a constant Element("") // BCF3009: empty Element("my widget") // BCF3009: not spelled like a tag name
A tag name is an ASCII letter, then ASCII letters, digits, -, _ or ..
The constant half keeps the element declarative: a computed tag is neither an injection risk nor a sequencing problem, but the element no longer names its tag where you wrote it.
The spelling half is a translation break. A tag no element can be named renders as two different
things: prerendering writes it into markup where the HTML parser reinterprets it, while interactive
rendering hands it to createElement, which rejects it and ends the circuit.
BCF1006#
Error. A static ElementView property used as an element tag alias is declared in a referenced
assembly.
// In a referenced project or NuGet package: public static ElementView MyCard => Element("my-card"); // In this compilation: MyCard["content"] // BCF1006
The generator resolves an alias by reading its own declaration's syntax — Element("my-card") — to
find the tag. IL carries no body, so a declaration reached through a referenced assembly has nothing
to read. Declare the alias in the current compilation instead:
static ElementView MyCard => Element("my-card"); MyCard["content"] // fine
A [ViewPart] reaches the same wall for the same reason (BCF1002): both features read
their own source, not the target's, so both stop at the compilation boundary.
BCF3016#
Error. Children were written on a void element.
Img.Src("/logo.png")["Logo"] // BCF3016 Element("img")["Logo"] // BCF3016, same rule Img.Src("/logo.png").Alt("Logo") // what to write instead
The thirteen void elements are area, base, br, col, embed, hr, img, input, link,
meta, source, track, wbr.
The children do not survive a round trip through HTML. Prerendering serializes a closing tag the
parser does not accept, so the parser moves the children out and they become the element's
siblings. A stray </br> is re-read as a start tag, so Br["x"] prerenders as two <br>
elements.
Interactive rendering has no parser in between and puts the same children inside. One expression produces two different DOM trees, and the page changes shape at hydration.
Configure a void element with decorations and put content beside it.
Both spellings are checked, the helper and Element with a void tag. Custom elements and unknown
tags are not: Element("img-viewer")["child"] is accepted, because there is no standard to read
their content model out of.
This is the limit of what the surface checks about HTML, and the limit is deliberate. BCF3016 is
decidable from the element tag by itself. Whether a particular child is allowed inside a particular
parent is not, so Table[Div["x"]] is accepted along with attributes an element does not define.
BCF3027#
Error. A declaration of your own took the simple name the element helper wanted.
[Parameter] public string Data { get; set; } Div[Data["Heading"]] // BCF3027, a member public sealed class Table; // Table["x"] — BCF3027, a type namespace MyApp.Article { } // Article["x"] — BCF3027, a namespace private string Summary() => ""; // Summary["x"] — BCF3027, a method Div[Html.Data["Heading"]] // what to write instead
using static BlazorCodeFirst.Html; imports every conforming HTML element name, and a declaration
of your own wins simple-name lookup over an imported one. Blazor parameters named Label, Data,
Summary or Source are ordinary, so this happens.
C# has an error for every one of these — CS1503 on the index argument, CS0119, CS0118, CS0021 — and
none of them is reported. As long as the body does not translate, the component has no generated
RenderView, so the compiler stops before it binds method bodies, which is where all four are
found.
Decorations#
BCF3008#
Error. A decoration was applied to something that opens no element.
If(_open, () => Div["x"]).Class("card") // BCF3008 Div["text"].Class("card") // BCF3008: the brackets already produced a View Div.Class("card")["text"] // what to write instead
A decoration folds into the owning element's attributes, so it needs an element to attach to.
If, ForEach, Fragment, Raw, and a [ViewPart] or component result open none.
BCF3026#
Error. The name written in a decoration's position is not one this library declares.
Div.Clas("card") // BCF3026 Div.Class("card") // what to write instead
A misspelling reaches this, and so does an extension method of your own that takes an element and gives one back. C# has an error for the misspelling, and the same declaration-stage stop prevents it being reported.
BCF3010#
Error. An attribute or event is bound more than once on one element.
Input.Type("text").Attr("value", _a).Attr("value", _b) // BCF3010 Input.Type("text").Attr("value", _b) // what to write instead Div.Class("card").Class("is-open") // fine: class folds
Two bindings in the attribute channel discard the earlier one, because the last write wins. One name bound through the attribute channel and once through the event channel keeps both, so an inline handler and a C# handler each fire on every event. Neither is what you wrote.
class is the sole exception: .Class and .Attr("class", …) fold into one space-joined
attribute. style is not an exception, so two of them on one element is BCF3010.
BCF3011#
Error. The .Attr name or .On event name is not a non-empty compile-time constant string.
Div.Attr(_name, "x") // BCF3011 Div.Attr("data-kind", "x") // what to write instead
The name lowers to a literal, and holding it to a constant is also what makes class folding and duplicate-binding detection possible.
BCF3023#
Error. A decoration written on class carries a value the class channel cannot join as text.
Div.Attr("class", _selected) // BCF3023 Div.Attr("class") // BCF3023: a presence has no text Div.Class(_selected ? "is-selected" : null) // what to write instead
The class channel joins its decorations into one value as text, so class takes a string and
nothing else. The bool overload of .Attr is Blazor's conditional-attribute form, and the bare
.Attr(name) spelling stands for a presence; neither is text.
The value would otherwise translate two different ways. With one class decoration on the element the
channel emits the value alone, so true renders class="" and empties the class list. With two or
more the channel joins them with +, so the same true renders class="a True". One spelling
meaning two things depending on a count written elsewhere in the chain is the defect.
BCF3024#
Error. One element carries both a class-channel decoration and a .Bind on class.
Div.Class("card").Bind("class", "onchange", () => _classes) // BCF3024
.Class and .Attr("class", …) fold into a single attribute. A .Bind on the same name does not
join that fold; it emits its own frame, so the element is emitted with class twice.
Which one survives has no single answer: prerendered markup is resolved by the HTML parser, which keeps the first, while an interactive render applies them through the DOM, where the last write stands.
Supply the whole class value from one place. Bind it alone and let the getter carry everything, or drop the binding and use the decorations.
BCF3033#
Error. The same non-attribute decoration is written twice on one node.
Div.Key(row.Id).Key(row.Slug)["x"] // BCF3033 Div.Key(row.Id)["x"] // what to write instead
.Key and its siblings each occupy a channel that holds one value. All three break differently, and
none of them breaks visibly:
SetKeywrites into the open frame, so the second call overwrites the first.AddComponentRenderModeappends, and the renderer reads the first frame it finds, so there the second one is ignored.- A reference capture appends too, and both actions run.
Write the decoration once, with the value the node should carry. Two candidate keys mean the identity is not decided, and the source is the only place where deciding it is visible.
BCF3034#
Error. The component's own declaration fixes its render mode, so the call site cannot set one.
Component<Counter>().RenderMode(RenderMode.InteractiveWebAssembly) // BCF3034 if Counter declares one
The framework rejects the pair: ComponentFactory throws when a type carrying a
RenderModeAttribute also receives a caller-specified mode. The call-site form exists for a
component that declares no mode of its own, which is the case where it is needed: the same component
rendered interactively from one page and statically from another.
Drop the .RenderMode at the call site and let the component's own attribute apply. If the mode
genuinely has to vary by caller, remove the attribute from the component instead, and then every
call site must name a mode.
BCF3039#
Error. .FormName's argument is a literal empty string or null.
Form.FormName("")["submit"] // BCF3039 Form.FormName("save")["submit"] // what to write instead
.FormName lowers to AddNamedEvent("onsubmit", name), and the framework throws at run time for
either shape: ArgumentException for an empty name, ArgumentNullException for a null one. A
runtime expression is not required to be a compile-time constant — only a literal known ahead of
time to always throw is rejected here.
BCF3040#
Error. .FormName is written on an element whose tag is not form.
Div.FormName("save")["submit"] // BCF3040 Form.FormName("save")["submit"] // what to write instead
.FormName lowers to AddNamedEvent("onsubmit", …), and onsubmit is a browser-native event that
only ever fires on a <form> element. A registration on any other tag is never reached.
Events#
BCF3019#
Error. The event name does not begin with on.
Input.On("input", (ChangeEventArgs e) => …) // BCF3019 Input.On("oninput", (ChangeEventArgs e) => …) // what to write instead
Blazor's event attribute names always begin with on, and the prefix is never added for you. A name
without it reaches AddAttribute as an ordinary attribute, so the handler is never called and
nothing reports it at runtime.
On .Bind this does a second job. The attribute name and the event name are adjacent string
arguments, so swapping them compiles; this is what stops a swapped pair.
BCF3028#
Error. The handler's argument type is not one the named event delivers.
Button.On("onclick", (MouseEventArgs e) => Zoom(e.ClientX, e.ClientY))["Zoom"] // the delivered type Button.On("onclick", (EventArgs e) => Save())["Save"] // a base of it: fine Button.On("onclick", (KeyboardEventArgs e) => Save())["Save"] // BCF3028
Blazor dispatches an event by casting its argument object to the handler's argument type, so a base
of the delivered type is accepted and a sibling is not. A type that is not an EventArgs at all is
the same diagnostic.
The mapping is read from the [EventHandler] metadata the framework ships and from any registration
in the compilation being built. An event with no entry has no mapping and is not checked:
[EventHandler("onrate", typeof(RatingEventArgs))] public static class AppEventHandlers;
BCF3035#
Error. An event modifier has no event before it on the element.
Form.PreventDefault().On("onsubmit", () => Save()) // BCF3035 Form.On("onsubmit", () => Save()).PreventDefault() // what to write instead
.PreventDefault and .StopPropagation attach to the event written before them, which is the only
reading a chain offers: the decorations carry no event name of their own.
BCF3036#
Error. The same event modifier is written twice for one event.
Form.On("onsubmit", () => Save()).PreventDefault().PreventDefault() // BCF3036 Form.On("onsubmit", () => Save()).PreventDefault() // what to write instead
One of the two has no effect whichever way the model takes it, and which one is not visible at the call site.
Write the modifier once. It is a flag rather than a value, so a second one requests nothing the first did not already do.
BCF3038#
Error. The event's own [EventHandler] registration disables that modifier.
Blazor gates each modifier per event, and the renderer ignores an attribute the registration disabled. Remove the modifier; the event itself is correct and stays.
Control flow#
BCF3002#
Warning. The ForEach key selector does not reference its item, so it cannot identify one.
ForEach(rows, key: r => 0, content: r => Li[r.Name]) // BCF3002 ForEach(rows, key: r => r.Id, content: r => Li[r.Name]) // what to write instead
A key derived from the item is what lets Blazor preserve per-row state across insertion, removal, and reordering. A constant, an external index, or another list's item forces a full re-render.
The check is deliberately conservative: it does not detect an item-derived key that is index-like in practice.
BCF3003#
Error. The ForEach content root is not a single element or component, so the key has nothing to
attach to.
ForEach(rows, key: r => r.Id, content: r => If(r.Visible, () => Li[r.Name])) // BCF3003 ForEach(rows, key: r => r.Id, content: r => Li[If(r.Visible, () => Span[r.Name])]) // what to write instead
The key is applied to the content root's frame, and SetKey keys the currently open element or
component frame. A bare If, a nested ForEach, bare text, a Fragment, a Raw, and an
externally supplied RenderFragment all open no single keyable frame.
Wrap the content in a container element. A ForEach that declines its key with key: null emits no
SetKey, so those roots are allowed there.
BCF3004#
Error. The ForEach key or content has a shape the generator cannot sequence.
The key body is copied into the SetKey call, so it has to be an expression. The content is given
one static sequence space that every iteration reuses, which a second return would need its own
copy of.
Content accepts an expression lambda, a block with one trailing return, a block ending in a native
if/else (BCF2002), a block ending in a native switch (BCF2002), and a
single-parameter View-returning method group. A native foreach is not accepted here either, but
for a different reason: content is always a lambda, and a lambda cannot be a C# iterator block, so
yield return inside one is invalid before this diagnostic is reached. The equivalent shape is
accepted only on a [ViewPart] method, as an iterator
(control flow).
The key body and the content body follow the same reserved-name rule BCF1004 states for its getter.
BCF2002#
Info. A native if/else or switch degrades to a dynamic region.
protected override View Body { get { if (_flag) // BCF2002: correct, but not statically assigned { return Span["yes"]; } else { return Span["no"]; } } }
A native if/else or switch can be written as the last statement of a Body/Chrome getter, a
ForEach content lambda, or a [ViewPart] body. It is transplanted whole into a region whose
boundary sequence is fixed to syntactic position — the same shape If() uses. Unlike If(), each
arm's or section's content renders through a freshly synthesized RenderFragment rather than a
statically assigned sequence range. Only one arm or section ever executes, so no static width can be
reserved for content that might not run. Correctness is unaffected; the frames for whichever one runs
are rebuilt rather than diffed against a static template.
Reported once per if/else chain or switch, at the outermost if or at the switch's
discriminant, regardless of how many else if links or case sections it holds. A switch section's
own return is what closes it; each section still needs an explicit break in the generated code so
control does not fall through into the next one.
foreach is never reported here, in any position. At the getter and ForEach content positions
(BCF1004/BCF3004) it stays rejected — not by this diagnostic's own logic, but
because a property getter and a lambda cannot be C# iterator blocks, so yield return is invalid
there regardless. On a [ViewPart] method it is accepted instead, as an iterator
(control flow) — but it does not degrade the way
if/switch do: its content is one static sequence range every iteration reuses, the same as
ForEach's own content, so it never loses static assignment and this diagnostic never applies to it.
BCF3032#
Error. The ForEach content root writes its own .Key while the loop also applies one.
ForEach(rows, key: r => r.Id, content: r => Li.Key(r.Id)[r.Name]) // BCF3032
Two SetKey calls land on one frame, of which the second wins, so which key is authoritative
depends on emission order rather than on anything at the call site. Key the root or key the loop.
BCF3043#
Error. A loop's source argument resolves to a call to a [ViewPart].
[ViewPart] private static IEnumerable<View> Rows(IReadOnlyList<Item> items) => ...; ForEach(Rows(items), key: item => 0, content: item => item) // BCF3043 Ul[.. Rows(items)] // what to write instead
A [ViewPart]'s body is built from the design-time surface, which is inert at runtime. Called from
a loop's source position, it runs as ordinary code against that inert surface instead of being
statically expanded, so the loop count comes out right but every yielded item comes out empty.
This is also reported when the call is reached indirectly — through an intermediate local, a
.ToList(), a null-forgiving suffix, a parenthesization, a cast, or an as conversion — since the
same runs-against-an-inert-surface failure follows the call wherever it ends up:
var rows = Rows(items); ForEach(rows, key: item => 0, content: item => item) // BCF3043 Ul[.. Rows(items)] // what to write instead -- remove the local too
This also applies to a spliced projection's own source (Ul[.. Rows(items).Select(item => ...)]) and
to a native foreach inside another [ViewPart] iterator's own body — the same failure at every
loop-header position a [ViewPart] call can be written at.
An iterator [ViewPart] has exactly one supported call spelling: a spread in a child position.
Rewrite the loop source as a spread there instead.
BCF3044#
Error. An If branch has a shape the generator cannot sequence.
If(_flag, delegate() { return Span["yes"]; }) // BCF3044 If(_flag, () => Span["yes"]) // what to write instead
Each branch accepts an expression lambda, a block with one trailing return, a block ending in a
native if/else (BCF2002), a block ending in a native switch (BCF2002),
and a zero-parameter View-returning method group. This is the same five shapes ForEach's content
accepts (BCF3004). An anonymous method is excluded outright: it names no callee a method
group could be read as, and it is not one of the lambda shapes either.
The branch follows the same reserved-name rule BCF1004 states for its getter.
Components#
BCF3005#
Error. The parameter selector is not a simple property selection on its own lambda parameter.
Component<Card>().Param(c => (string)c.Label, "x") // BCF3005 Component<Card>().Param(c => c.Label, "x") // what to write instead
The generator reads the parameter's name out of the selector's spelling, so a cast, a method call, a
null-conditional access, or a member of a captured variable has no name to read. .Param,
.Template, and .Bind all take that same selector.
BCF3006#
Error. The selected property is not a settable [Parameter].
public string Label { get; set; } // BCF3006: no [Parameter] [Parameter] public string Label { get; } // BCF3006: no setter [Parameter] public string Label { get; set; } // what to write instead
Only a property marked [Parameter] with an accessible setter can be bound. Setting anything else
would throw when Blazor applies the parameters.
Mark the property [Parameter] and give it an accessible setter. A value the component should not
receive from its caller belongs in a field rather than in a parameter.
BCF3007#
Error. The chain binds the same parameter more than once.
Component<Card>().Param(c => c.Label, "a").Param(c => c.Label, "b") // BCF3007 Component<Card>().Param(c => c.Label, "b") // what to write instead
Every channel counts: .Param, .Template, .Bind, and child content written in brackets. Blazor
applies the last write, so the earlier value is discarded.
Bind the parameter once, with the value the component should end up with. A value that depends on
state belongs in the expression you pass, not in a second .Param.
BCF3012#
Error. The type argument did not resolve while the generator ran.
The usual cause is a .razor component declared in the same project. The Razor compiler is itself a
source generator, and source generators cannot observe each other's output, so the type is
unresolved here even though it exists in the final compilation.
Move it to a referenced project, write it as a hand-authored C# component, or fix the name. The same component in a referenced project or a NuGet package resolves normally.
A typo, an inaccessible type, an ambiguous name, or a missing using reaches this too, and a C#
resolution error is reported at the same position.
BCF3013#
Error. Child content was written in brackets on a component that cannot receive it.
Component<Panel>()["body"] // BCF3013 if Panel has no ChildContent Component<Panel>().Param(c => c.Content, Span["body"]) // what to write instead
Brackets bind to a parameter named ChildContent, mirroring how Razor lowers nested content. It has
to be a settable [Parameter] typed RenderFragment or RenderFragment<TContext>; the generic one
receives the children with its context discarded.
BCF3014#
Error. An inert design-time value was passed to the generic Param.
Component<Card>().Param(c => c.Body, Div["x"]) // BCF3014 Component<Card>().Param(c => c.Body, () => Div["x"]) // what to write instead
View and ComponentView<T> are empty markers read by the generator, not runtime values. The
generic Param emits its value expression verbatim, so binding one assigns the marker: an
object-typed parameter accepts it with no exception and renders wrong output, while a typed
parameter throws an invalid cast when Blazor applies parameters.
BCF3022#
Error. The contextual .Template content has a shape the generator cannot sequence.
Component<Grid<Row>>().Template(c => c.RowTemplate, delegate(Row row) { return Td[row.Name]; }) // BCF3022 Component<Grid<Row>>().Template(c => c.RowTemplate, row => Td[row.Name]) // what to write instead
Content accepts an expression lambda, a block with one trailing return, a block ending in a native
if/else (BCF2002), a block ending in a native switch (BCF2002), and a
single-parameter View-returning method group. This is the same five shapes ForEach's content
accepts (BCF3004). An anonymous method is excluded outright: it names no callee a method
group could be read as, and it is not one of the lambda shapes either.
The content follows the same reserved-name rule BCF1004 states for its getter.
BCF3025#
Error. Slot is written outside the body of a content-taking [ViewPart], or named other than
exactly once.
[ViewPart] public static SlotView Panel(View heading) => Section[heading, Div.Class("body")[Slot]]; // fine protected override View Body => Div[Slot]; // BCF3025: Body receives no brackets
Slot marks where a part places the content its caller supplied in brackets, so it means nothing
where there is no caller content: a component's Body or Chrome receives no brackets, and a part
returning View is called without them.
A part that takes content declares SlotView as its return type and names Slot exactly once.
Naming it twice would emit the caller's content twice; not naming it at all would discard content
the caller was required to supply.
BCF3042#
Error. .Class/.Attr, or one of the Id/Type/Title/Role/Href/Src/Alt shortcuts, on a
component call names, case-insensitively, a parameter the component declares.
Component<Card>().Attr("label", "hi") // BCF3042: Card declares [Parameter] Label Component<Card>().Param(c => c.Label, "hi") // what to write instead
Blazor matches an attribute name against a component's declared parameters case-insensitively, so
"label" would otherwise silently set Label at runtime instead of landing in
AdditionalAttributes — bypassing .Param's type checking and giving no signal that it happened.
Bind the parameter with .Param instead, so the value is checked against its declared type.
Two-way binding#
BCF3017#
Error. The .Bind getter is not an inline lambda with an expression body.
Input.Bind("value", "oninput", GetName) // BCF3017 Input.Bind("value", "oninput", () => _name) // what to write instead
The getter's body is copied into two places, once as the bound attribute's value and once as the binder's current value, so it has to be available as an expression. A block-bodied lambda and a method group both hide it behind a call.
The setter argument carries no such restriction, because it is handed to EventCallback whole and
never taken apart.
BCF3018#
Error. The getter-only .Bind's getter body cannot be assigned to, so no setter can be derived.
Input.Bind("value", "oninput", () => Name.Trim()) // BCF3018 Input.Bind("value", "oninput", () => Name, v => Name = v.Trim()) // what to write instead
The getter-only form derives its setter by placing the getter's body on the left of an assignment, so that body has to be a field, a settable property, or an element access whose indexer has a setter.
A setter existing is not the same as the derived assignment being able to call it. The derived
setter is a lambda, so an init accessor is out of reach: C# admits one only in an object
initializer, a constructor, or another init accessor. A setter declared narrower than the property
that carries it is out of reach too, this time depending on where the assignment lands.
{ get; private set; } on the component itself is accepted, because the generated RenderView is
emitted into a partial of that same class; the same property on another type is not.
A local, a parameter, and a ForEach iteration variable are rejected even though C# would assign to
them: the design-time expression is a property getter, so those go out of scope with each render and
the write-back would not survive to the next one. A member of an iteration variable is accepted,
because it writes through to the element in the source list.
BCF3020#
Error. The component declares no matching change callback, so a two-way binding has nowhere to write back.
Component<Field>().Bind(c => c.Value, () => _query) // BCF3020 without ValueChanged Component<Field>().Param(c => c.Value, _query) // what to write instead, one way
Component binding derives its parameter names rather than taking them from you, which is the
opposite of the element surface. That is sound only because the derivation can be checked: the
component's type is known, so the generator looks up {name}Changed and reports this when it is
absent or carries the wrong type.
Element binding has no such check available, which is why it makes you write both names.
BCF3031#
Error. .Bind writes a format for a value type the framework declares no format-taking converter
for.
Input.Bind("value", "oninput", () => _count, format: "N0") // BCF3031
BindConverter.FormatValue and CreateBinder declare their format-taking overloads for DateTime,
DateTimeOffset, DateOnly, TimeOnly and their nullable forms only. A format on anything else
would leave the generated file with a call that does not bind, and that C# error is raised inside
generated code rather than in the source you wrote.
Drop the format, or format the value in the getter and parse it in an explicit setter. The set is read from the framework's own metadata rather than enumerated by this compiler, and the culture is not in question: every type this surface binds may carry one.
Scoped CSS#
BCF3041#
Error. A Foo.cs.css file has no matching Foo.cs, and Foo.cs declares neither a component nor a
[ViewPart] method.
Counter.cs.css // scopes nothing: no Counter.cs in this project // BCF3041
A .cs.css file's scope is discovered by matching its name against a .cs file — there is no
explicit way to pair the two, unlike Razor's ScopedCssInput. An unmatched file is therefore always
a mistake, most often a typo in the file name, so it is reported rather than silently dropped.
Rename the .cs.css file to match the component (or the file declaring the [ViewPart] methods)
whose elements it is meant to scope, or add that file if it does not exist yet.
Next#
Back to getting started, or read the element vocabulary.