Skip to content

Diagnostics

Every problem the compiler finds is reported as a diagnostic: a severity, a stable code, a message, and the line and column it came from. This page is the catalogue of those codes.

A message is written for a person and gets reworded whenever a clearer wording is found. A code never changes. So a code is what you match on, suppress on, and group by - anything reading the message text breaks the next time the message is improved.

The CLI prints a diagnostic in the format editors and build servers already parse - the file, the position, the severity, the code, and the message - followed by the offending line and a caret:

nested/broken.play(3,5): error PLAY0028: Unknown slice type 'Wat' - expected StateChange, StateView, Automation or Translate
3 | slice Wat DoIt
| ^

There are three severities. Error means the document does not compile. Warning means the document compiles but something is very likely wrong - almost always a name nothing declares. Information means something worth knowing that changes nothing.

The prefix is PLAY, after the .play documents this compiler reads.

Cratis Arc has its own catalogue, the SP codes, for generating a .play document from C# source. The two run one after the other - Arc generates a document and hands it straight to this compiler to read back - so both sets of diagnostics land in the same build log. A shared prefix would make SP0034 and a compiler code of the same number indistinguishable at a glance and identical to a SP\d{4} filter, which is why the prefixes deliberately have nothing in common. Arc’s codes describe what the generator could not express; the codes here describe what the compiler could not read.

A code is an identifier, not a position in a list.

  • A number is never reused. When a diagnostic is retired, its number is retired with it and left behind as a gap in the sequence. Handing that number to something else would silently change what an existing suppression means.
  • A number is never renumbered. Inserting a code in the middle of the catalogue would change the meaning of every code after it.
  • A new code is appended at the end of the sequence whatever it is about, so the number says when a code was added rather than where it belongs. Use this page, not the numbering, to find the codes for an area.
  • A code outlives its message. Two constructs hitting the same condition share one code - a property line the parser cannot read reports PLAY0016 whether it sits in a type or in an event.

Diagnostic carries the code alongside the severity, the message and the location, so a consumer filters on it directly:

using Cratis.Screenplay;
using Cratis.Screenplay.Diagnostics;
var result = new ScreenplayCompiler().Compile(source);
// A document assembled a piece at a time refers to events the pieces have not introduced yet,
// so that one warning is expected here and everything else is not.
var unexpected = result.Diagnostics
.Where(diagnostic => diagnostic.Code != DiagnosticCodes.UnknownEvent)
.ToList();

DiagnosticCodes declares every code in this catalogue as a named constant, so the compiler catches a typo that a string literal would not.

The language service behind the VS Code extension and the Monaco editor checks a subset of what the compiler checks, and it reports the compiler’s code for every condition in that subset. So the Unknown type 'Foo' you get as a squiggle and the one the CLI prints are the same PLAY0165, and can be looked up here, filtered on, and matched against a build log:

import { diagnosticCodes, validateLines } from '@cratis/screenplay-language';
const unknownTypes = validateLines(lines).filter((issue) => issue.code === diagnosticCodes.unknownType);

diagnosticCodes names the codes the editor reports, the same way DiagnosticCodes names them for the compiler. A ValidationIssue carries the code as code, and it reaches the editor: a Monaco marker gets it as code, a VS Code diagnostic as Diagnostic.code.

A few editor checks carry no code, deliberately. The capture and projection validators enforce structural rules that no compiler run reports - a capture must include a source block, an append block must include a when clause - and there is no PLAY number for something the compiler never emits. Minting one would make this catalogue describe two different tools, which is the thing the PLAY prefix was chosen to avoid. Those conditions are reported without a code until the compiler checks them too.

CodeSeverityReported when
PLAY0001ErrorA line at the top level of a document opens with a word nothing at that level is declared by.
PLAY0002ErrorA domain line is not domain <Qualified.Name>.
PLAY0003ErrorA document declares a domain more than once, and a document has at most one.
PLAY0004Errordomain is declared after another construct, and it names what the whole document is about.
PLAY0005ErrorAn import line is not import <Qualified.Name>.
PLAY0006WarningA line is indented with tabs, and Screenplay decides nesting from spaces.
CodeSeverityReported when
PLAY0007ErrorA concept line is not concept <Name> : <Type>.
PLAY0008ErrorA concept is declared over a primitive the language does not have.
PLAY0009ErrorA value of an enumeration concept is not an identifier.
PLAY0010ErrorA line in a concept body opens with a word a concept declares nothing by.
PLAY0011WarningA value of an enumeration is called validate, which the concept body reads as an empty validate block.
PLAY0012ErrorA concept gives the reason for an attribute it does not carry.
PLAY0013ErrorA concept gives the reason for one attribute more than once.
CodeSeverityReported when
PLAY0014ErrorA type line is not type <Name>.
PLAY0015ErrorA type declares no properties, and a type is the properties it holds.
PLAY0016ErrorA property line is not <name> <Type>.
PLAY0017ErrorA property outside a command is marked as the identifier, which only a command property can be.
CodeSeverityReported when
PLAY0018ErrorAn event line is not event <Name>.
PLAY0019ErrorA property of an event is marked as the identifier, and an event never carries its event source id.
PLAY0020WarningA property called tag is read by the event body as a static tag rather than as a property.
CodeSeverityReported when
PLAY0021ErrorA module line is not module <Name>.
PLAY0022ErrorA line in a module body opens with a word a module declares nothing by.
PLAY0023ErrorA feature line is not feature <Name>.
PLAY0024ErrorA line in a feature body opens with a word a feature declares nothing by.
PLAY0025ErrorA slot declared by a layout, screen template or dialog template is not an identifier optionally followed by contributes.
PLAY0026ErrorA line in a layout, screen template or dialog template body opens a block none of them declares anything by.
PLAY0027ErrorA slice line is not slice <Type> <Name>.
PLAY0028ErrorA slice is declared with a type the language does not have.
PLAY0029WarningA line in a slice body opens with a word a slice declares nothing by.
CodeSeverityReported when
PLAY0030ErrorA persona line is not persona <Name>.
PLAY0031ErrorA policy line in a persona body is not policy <Name>.
PLAY0032ErrorA line in a persona body opens with a word a persona declares nothing by.
CodeSeverityReported when
PLAY0033ErrorA command line is not command <Name>.
PLAY0034ErrorA line in a command body opens with a word a command declares nothing by.
PLAY0035ErrorA command declares both produces and handler, which say the same thing two ways.
PLAY0036ErrorA command marks more than one property as its identifier.
PLAY0037ErrorA concurrency line carries anything beyond the keyword.
PLAY0038ErrorA command declares more than one concurrency block, and a command has at most one.
PLAY0039ErrorA line in a concurrency block names a dimension the block does not have.
PLAY0040ErrorA dimension of a concurrency block is not written the way that dimension is written.
PLAY0041ErrorA concurrency block states one dimension more than once.
PLAY0042ErrorA produces line is neither produces <EventType> nor produces when <condition>.
PLAY0043ErrorA produces when condition is followed by no event to produce.
PLAY0044ErrorA mapping line is not <property> = <source>.
PLAY0045ErrorA handler names neither a file nor an inline code block.
PLAY0046ErrorA line in a handler body opens with a word a handler declares nothing by.
CodeSeverityReported when
PLAY0047ErrorA query line is not query <Name> => [observable] <ReadModel>.
PLAY0048ErrorA line in a query body opens with a word a query declares nothing by.
PLAY0049ErrorA by or filter parameter is not <keyword> <name> <Type> [from <source>].
PLAY0050ErrorA performer line carries anything beyond the keyword.
PLAY0051ErrorA query declares more than one performer, and a query has at most one.
PLAY0052ErrorA performer names neither a file nor an inline code block.
PLAY0053ErrorA line in a performer body opens with a word a performer declares nothing by.
CodeSeverityReported when
PLAY0054ErrorA projection document holds a top level line that does not open a projection.
PLAY0055ErrorA projection document declares no projection at all.
PLAY0056ErrorA projection line is not projection <Name> [=> <ReadModel>].
PLAY0057ErrorA projection declares no directives, so it builds nothing.
PLAY0058ErrorA line in a projection body opens with a word a projection declares nothing by.
PLAY0059ErrorA projection declares more than one key.
PLAY0060ErrorA from block declares more than one key.
PLAY0061ErrorA from line names no event to read from.
PLAY0062ErrorAn event reference is not a name the language can read as one.
PLAY0063ErrorA join line is not join <property> on <key>.
PLAY0064ErrorA join block holds a line that is not with <EventType>.
PLAY0065ErrorA children line is not children <collection> identified by <key>.
PLAY0066ErrorA nested line is not nested <property>.
PLAY0067ErrorA nested block reads from no event, so nothing ever fills it.
PLAY0068ErrorA remove line is neither remove with <EventType> nor remove via join on <EventType>.
PLAY0069ErrorA remove block holds a line other than parent.
PLAY0070ErrorA clear line is not clear with <EventType>.
PLAY0071Errorclear with is written where there is nothing to clear.
PLAY0072ErrorA part of a composite key is not <property> = <expression>.
PLAY0073ErrorA composite key part is a template expression, which a key cannot be.
PLAY0074ErrorA composite key declares no parts.
PLAY0075ErrorA mapping line in a projection is not one the language can read.
CodeSeverityReported when
PLAY0076ErrorA capture document holds a top level line that does not open a capture.
PLAY0077ErrorA capture document declares no capture at all.
PLAY0078ErrorA capture line is not capture <Name>.
PLAY0079ErrorA line in a capture body opens with a word a capture declares nothing by.
PLAY0080ErrorA map entry is not <property> = <source> [translate].
PLAY0081ErrorA translation is not "<source>" => <target>.
PLAY0082ErrorA split line is not split <property> by "<separator>".
PLAY0083ErrorA target of a split is not a property path.
PLAY0084ErrorAn append line is not append <EventType>.
PLAY0085ErrorA line in an append body opens with a word an append declares nothing by.
PLAY0086ErrorA when line names no trigger.
PLAY0087ErrorA when clause is not one of the shapes a trigger is written in.
PLAY0088ErrorA value transition is not when <Path> from <value> to <value>.
PLAY0089ErrorA when clause combines properties with both and and or.
PLAY0090ErrorA when combinator is followed by no property.
PLAY0091ErrorA line in a children or nested block is neither map nor append.
CodeSeverityReported when
PLAY0092ErrorA specification document holds a top level line that does not open a specification.
PLAY0093ErrorA specification document declares no specification at all.
PLAY0094ErrorA specification line is not specification <Name>.
PLAY0095ErrorA line in a specification body opens with a word a specification declares nothing by.
PLAY0096ErrorA when line is not when <CommandType>.
PLAY0097ErrorA specification issues more than one command, and a specification is one example.
PLAY0098ErrorA then error line is neither then error nor then error "<reason>".
PLAY0099ErrorA given readmodel or then readmodel line does not name a read model type.
PLAY0100ErrorA given or then line does not name an event type.
PLAY0101ErrorA value a specification step states is not <property> = <value>.
CodeSeverityReported when
PLAY0102ErrorA screen line is not screen <Name>.
PLAY0103ErrorA line in a screen body opens with a word a screen declares nothing by.
PLAY0104ErrorA data line is not data <ReadModel> via query <Query> [by <param>].
PLAY0105ErrorAn action line is not action <Command>.
PLAY0106ErrorA line in an action body is neither label nor navigate to.
PLAY0107ErrorA navigation is not navigate to <Screen> [by <param>].
PLAY0108ErrorA line under a screen layout does not name a slot.
PLAY0109ErrorA title line is not title "<text>".
PLAY0110ErrorA line in a table body is neither column nor on row-click navigate to.
PLAY0111ErrorA line in a summary body is not field <property> label "<text>".
CodeSeverityReported when
PLAY0112ErrorA policy line is not policy <Name>.
PLAY0113ErrorA line in a policy body is neither require nor an inline code block.
PLAY0114ErrorA policy states nothing it requires of the caller.
PLAY0115ErrorA policy condition holds a token the language has no reading for.
PLAY0116ErrorA policy requirement states no condition.
PLAY0117ErrorA group opened in a policy condition is never closed.
PLAY0118ErrorA role requirement names no role.
PLAY0119ErrorA claim requirement names no claim.
PLAY0120ErrorA claim requirement does not say what the claim is matched against.
PLAY0121ErrorA claim match states nothing to match the claim to.
PLAY0122ErrorAn authorize clause names no policy.
PLAY0123ErrorA policy is referred to by something that is not a policy name.
CodeSeverityReported when
PLAY0124ErrorAn authentication line carries anything beyond the keyword.
PLAY0125ErrorA document declares more than one authentication block, and a document has at most one.
PLAY0126ErrorA provider line is not provider <Name>.
PLAY0127ErrorA setting of a provider is not <name> <value>.
CodeSeverityReported when
PLAY0128ErrorA seed line carries anything beyond the keyword.
PLAY0129ErrorA seed group is not for "<event source id>".
PLAY0130ErrorA line in a seed group does not name an event type.
PLAY0131ErrorA value a seeded event carries is not <property> = <value>.
CodeSeverityReported when
PLAY0132ErrorA constraint line is not constraint <Name>.
PLAY0133ErrorA constraint states nothing it holds the application to.
PLAY0134ErrorA line in a constraint body is not one the language can read.
PLAY0135ErrorA constraint states more than one rule, and a constraint states one.
CodeSeverityReported when
PLAY0136ErrorA reaction line is not reaction <Name>.
PLAY0137ErrorA line in a reaction body is not a trigger the language reads.
PLAY0138ErrorA reaction states no trigger, so nothing ever sets it off.
PLAY0139ErrorA line in a reaction trigger body opens with a word a trigger declares nothing by.
CodeSeverityReported when
PLAY0140ErrorA validate line is neither validate nor validate csharp.
PLAY0141ErrorA validation rule is not one the language can read.
PLAY0142ErrorA validation rule names a rule the language does not have.
PLAY0143ErrorA rule line does not name the rule with an identifier.
PLAY0144ErrorA named rule names neither a file nor an inline code block.
CodeSeverityReported when
PLAY0145ErrorA description line is not description "<text>".
PLAY0146ErrorA fenced description holds no text.
PLAY0147ErrorSomething is described more than once, and a description is given once.
PLAY0148ErrorA tag line carries no value.
PLAY0149ErrorA tag value is neither an identifier, a string literal nor a context expression.
CodeSeverityReported when
PLAY0150ErrorA literal expression carries no value.
PLAY0151ErrorA $causedBy expression names a property the cause does not carry.
PLAY0152ErrorAn expression is not one the language can read.
PLAY0153WarningA $context path opens with a root the context does not have.
PLAY0154WarningA $context.causedBy path names a property the cause does not carry.
PLAY0155WarningA $context.identity path names a property the identity does not carry.
PLAY0156ErrorA template expression is never closed.
PLAY0157ErrorAn interpolation inside a template expression is never closed.
CodeSeverityReported when
PLAY0158ErrorA condition holds a token the language has no reading for.
PLAY0159ErrorA condition is expected and nothing is written.
PLAY0160ErrorA group opened in a condition is never closed.
PLAY0161ErrorA comparison states what is compared and not how.
PLAY0162ErrorA comparison states nothing to compare against.
CodeSeverityReported when
PLAY0163ErrorA construct opening an inline code block is followed by no fence.
PLAY0164ErrorAn inline code block is never closed.
CodeSeverityReported when
PLAY0165WarningA property names a type nothing in the document or its imports declares.
PLAY0166WarningAn event is referred to that nothing in the document or its imports declares.
PLAY0167WarningA policy is referred to that nothing in the document declares.
PLAY0168ErrorA concept and a type, or two of either, are declared under one name.
PLAY0169ErrorAn authentication block declares two providers under one name.
PLAY0170ErrorA seed block seeds nothing.
PLAY0171ErrorA concurrency block narrows nothing.
CodeSeverityReported when
PLAY0172ErrorTwo files of a folder each declare something the application has at most one of.
PLAY0173ErrorTwo files of a folder declare the same name.
PLAY0174WarningTwo files of a folder describe the same thing differently, and the first description is kept.
CodeSeverityReported when
PLAY0175ErrorA reads line is not reads <ReadModel> or reads <ReadModel> by <property>.
PLAY0176ErrorA command declares that it reads the same read model more than once.
PLAY0177WarningA command reads a read model no projection in the document produces.
PLAY0178WarningThe by of a reads declaration does not name a property of the command.
CodeSeverityReported when
PLAY0179ErrorA require rule carries no condition.
PLAY0180ErrorThe body of a require rule holds something other than its message.
PLAY0181WarningA require operand is qualified by something the command does not read.
PLAY0182WarningA require operand names neither a property of the artifact nor state it reads.
CodeSeverityReported when
PLAY0183ErrorAn authentication provider carries a configuration body, which belongs where the application runs.
CodeSeverityReported when
PLAY0184ErrorTokens are left over after the requirement of an authorize.
PLAY0185ErrorA parenthesised group in an authorize is never closed.
CodeSeverityReported when
PLAY0186ErrorA readmodel line is not readmodel <Name>.
PLAY0187ErrorA reducer line is not reducer <Name> => <ReadModel>.
PLAY0188ErrorA line in a reducer body is not an on <EventType> rule.
PLAY0189ErrorA reducer declares no rule, so nothing it observes is stated.
PLAY0190ErrorThe body of a reducer rule holds something other than a description, a file or inline code.
PLAY0191ErrorMore than one projection or reducer builds the same read model.
PLAY0192ErrorA document declares the same read model more than once.

Where a produced event lands, and what a reaction sets off

Section titled “Where a produced event lands, and what a reaction sets off”
CodeSeverityReported when
PLAY0193ErrorA produces declares more than one for, and an event is appended to one event source.
PLAY0194ErrorAn invokes line is not invokes <Command>.
PLAY0195WarningA reactor invokes a command the document does not declare.
CodeSeverityReported when
PLAY0196WarningA screen binds data to a query nothing in scope declares.
PLAY0197WarningA screen navigates to a screen nothing in scope declares.
PLAY0198WarningA bare name matches more than one declaration at the same depth, so which one it means is undecided.
CodeSeverityReported when
PLAY0199ErrorA scoped line is not scoped to <scope>.
PLAY0200ErrorA query declares more than one scope, and results are narrowed one way.
CodeSeverityReported when
PLAY0201ErrorA ui profile line is not ui profile <Name>.
PLAY0202ErrorTwo ui profile blocks in the same document declare the same name.
PLAY0203ErrorA target line under a ui profile is neither target platform ... nor target size ....
PLAY0204ErrorA ui profile declares target platform or target size more than once.
PLAY0205ErrorA line under a packages block is not a valid package name.
PLAY0206ErrorA ui profile’s packages block lists the same package more than once.
PLAY0207ErrorA line in a ui profile body is not target or packages, or packages is declared more than once.
CodeSeverityReported when
PLAY0208ErrorA form line is not form <Name> for <Command>.
PLAY0209ErrorTwo form blocks in the same document declare the same name.
PLAY0210ErrorA line in a form body is not populate, field or on submit.
PLAY0211ErrorA populate line is neither populate via query ... nor populate from item.
PLAY0212ErrorA form declares populate more than once.
PLAY0213ErrorA field line is not field <property> [from <source>|compose using <Callback>] [label "..."].
PLAY0214ErrorAn on submit line is not on submit navigate to <Screen> [by <param>].
PLAY0215ErrorA form declares on submit more than once.
PLAY0216WarningA field binds to a property its form’s command does not declare.
CodeSeverityReported when
PLAY0217ErrorA contribute line is not contribute to <ContributionPoint>.
PLAY0218ErrorA line in a contribute to body is not navigate, label or order.
PLAY0219ErrorA contribution declares navigate to more than once.
PLAY0220ErrorA contribution declares label more than once.
PLAY0221ErrorA contribution declares order more than once.
PLAY0222ErrorA contribution’s label line is not label "..." or label $strings.....
PLAY0223ErrorA contribution’s order line is not order <number>.
PLAY0224WarningA contribution names a contribution point nothing in scope declares.
CodeSeverityReported when
PLAY0225ErrorA theme line is not theme <Name>.
PLAY0226ErrorTwo theme blocks in the same document declare the same name.
PLAY0227ErrorA line in a theme body is not compatible with <Package>.
PLAY0228ErrorA theme declares compatibility with the same package more than once.
PLAY0229ErrorA ui profile’s theme line is not theme <Name>.
PLAY0230ErrorA ui profile declares theme more than once.
PLAY0231WarningA ui profile selects a theme nothing in the document declares.
PLAY0232WarningA ui profile selects a theme not declared compatible with one of the profile’s own packages.
CodeSeverityReported when
PLAY0233ErrorAn arrangement line is not arrangement flow or arrangement freeform.
PLAY0234ErrorA layout, screen template or dialog template declares arrangement more than once.
PLAY0235ErrorA row, column or grid line in an arrangement is malformed.
PLAY0236ErrorA slot leaf within an arrangement tree has malformed sizing attributes.
PLAY0237ErrorA when override line in an arrangement is not a valid width/height size-class condition.
PLAY0238ErrorAn arrangement declares more than one when override for the same width/height size-class combination.
PLAY0239ErrorAn arrangement block’s body does not match its mode - a flow arrangement declares a variant, or a freeform arrangement declares anything other than one.
PLAY0240ErrorA variant line is not variant width <compact|regular>, height <compact|regular>.
PLAY0241ErrorAn arrangement declares more than one variant for the same width/height size-class combination.
PLAY0242ErrorA place line is not place <Slot> hidden or place <Slot> at x,y size w,h.
PLAY0243ErrorA variant places (or hides) the same slot more than once.
PLAY0244WarningA freeform arrangement’s variant does not mention (place or hide) a slot another variant of the same arrangement places.
CodeSeverityReported when
PLAY0245ErrorA trigger line is not trigger <Name>.
PLAY0246ErrorA line in a trigger body is neither a description nor a value the trigger provides.
PLAY0247ErrorThe document declares two triggers by the same name, leaving no answer to which one a reaction means.
PLAY0248WarningA when line names neither an event nor a trigger the document or the compiler knows.
PLAY0249ErrorAn every line is not every <n> <seconds|minutes|hours|days>.
PLAY0250ErrorAn at line is not at <HH:mm>, optionally followed by on <Weekday> or on day <n>.
PLAY0251WarningA reaction takes a value from an occurrence that the trigger does not provide.
PLAY0252ErrorA reaction states more than one where, and a reaction is narrowed by one condition.
PLAY0253ErrorA reaction declares the same trigger more than once, so the second says nothing the first did not.

Layouts, screen templates and dialog templates

Section titled “Layouts, screen templates and dialog templates”
CodeSeverityReported when
PLAY0254ErrorA screen template line is not screen template <Name>.
PLAY0255ErrorA dialog template line is not dialog template <Name>.
PLAY0256ErrorA fits slot line is not fits slot <name>.
PLAY0257ErrorA screen template declares fits slot more than once.
PLAY0258ErrorA layout or a dialog template declares fits slot - neither fills a slot of a parent structure.
PLAY0259ErrorA top level layout line is not layout <Name>.
PLAY0260ErrorA document declares more than one layout by the same name.
PLAY0261ErrorA ui profile’s layout line is not layout <Name>.
PLAY0262ErrorA ui profile declares layout more than once.
PLAY0263WarningA ui profile selects a layout nothing in the document declares.
CodeSeverityReported when
PLAY0264WarningA file directive names an absolute path, and a file reference is relative to the repository root.

A path that does not resolve is not a diagnostic, at any severity. A document is read in a designer, in a build and on a machine where the tree is not present, so the compiler never holds a path against a file system - a stale path must not be what makes a valid document invalid. A consumer that can resolve paths decides for itself what an unresolvable one means.

None yet. When a code is retired it is listed here with the release it went in, and its number stays out of use forever.