Skip to main content
Generated from the rslc compiler.

E-UNRESOLVED

Every name matches a declaration. A rater reads each value by name: an input, a calculation, a constant, a table, a type, an enum member or a function. The check asks every name to match a declaration the compiler has read. A misspelt name stops the check at its line and column. The rater then reads only values that exist, and a typing slip surfaces before any request is rated. The same code reports a file the compiler fails to read as a whole, such as a syntax error or a missing import. Example The premium reads rate_per_100, and the constant is named rate_per_1000.
Fix Spell the name as its declaration spells it.
Other causes
  • A misspelt input or calculation after self. gets unknown attribute 'payrol' on current entity.
  • A misspelt function gets a message that names it and lists the functions RSL has.
  • A misspelt type gets unknown type 'Mony'.
  • A lookup of a table that Tables lacks gets unknown table 'BaseRate'.
  • A misspelt enum or member gets unknown enum 'Teir' or unknown member 'prefered' in enum 'Tier'.
  • A Ref to a name that Records lacks gets `Ref(Driver)` names no record type.
  • An outcome that names a missing calculation gets rating outcome `premium` references unknown attribute `Policy.premum`.
  • A syntax error gets parse error in …: expected value, with the place where reading stopped.
  • An import of a missing file gets cannot resolve import "other.rsl", with the folders searched.
  • A name declared twice in one section gets duplicate Constants declaration 'rate_per_1000'.
bad/rater.rsl
good/rater.rsl

E-DATE

A date literal names a real calendar day. A date in a rater is written YYYY-MM-DD. The check asks each date literal in a calculation to name a day the calendar has. A date such as 2026-06-31 reads like a date and names a day that June lacks. The check reports it where it is written, so a comparison or a date difference always works from a real day. Example The rate changes on 2026-06-31, and June has 30 days.
Fix Write the day the filing means. Here the higher rate starts on 30 June.
bad/rater.rsl
good/rater.rsl

E-PATTERN

A match arm uses a pattern RSL knows. A match chooses a result by the value of its subject. Each arm starts with a pattern, and the pattern follows the subject’s type. An enum subject takes @Enum.member arms. A Bool takes true and false, an Option takes None and Some(x), and a union takes one arm per record type. _ matches every remaining value of an enum, Bool or Option. The check asks each arm to use one of these patterns, of the kind its subject takes. A pattern of another kind would match zero requests, so the compiler reports it instead of skipping the arm. Example The first arm names the enum member as the string "standard".
Fix Name the member with its enum, as @Tier.standard.
Other causes
  • None or Some(x) on a subject of another type gets `None` and `Some(…)` match an `Option`, with the subject’s type.
  • A capitalised arm such as Standard(s) on an enum gets arm pattern `Standard` matches a union input.
  • _ or @Enum.member on a union gets a union is matched arm by arm, by record type.
  • A union arm that names another record type gets `Unrted` is not an arm of this union, with the union’s arms.
bad/rater.rsl
good/rater.rsl

E-TYPE

Each value has the type its place expects. Every value in a rater has a type: a number, a Bool, a Date, an enum member, a record or a list. Each place that takes a value states the type it takes, such as the condition of an if or a key of a lookup. The check asks the two to agree. A number where a Bool belongs, or an enum member in arithmetic, is a mistake in the formula. The compiler reports it before any request is rated. RSL converts between types only where you write the conversion. A condition is a comparison such as self.payroll > 0, and an enum becomes a factor through a match or a table. Example The condition of the if is the number self.payroll, and an if takes a Bool.
Fix Write the condition as a comparison.
Other causes
  • A calculation whose value differs from its declared type gets attribute `premium` expects Premium, got Bool.
  • An enum member in arithmetic gets arithmetic operand expects Num.
  • A comparison of an enum with a number gets this comparison compares enum … with Num.
  • An ordering such as > on an enum gets only numbers and dates are ordered.
  • A lookup with more or fewer keys than the table has dimensions gets pass one key per dim, in order.
  • A lookup key of another type than its dimension gets lookup argument 1 of … takes a number.
  • A read through a list, such as self.items.charge, gets is a list of instances; bind the list in a fold such as sum.
  • A read through a field that holds a plain value, such as self.payroll.amount, gets is not an entity navigation field.
  • A [key] after a value that is a single number gets attribute `item_charge` is not indexed.
  • None as the value of a calculation of a plain type gets `None` requires expected type Option(T).
  • An enum that lists one member twice gets declares member … more than once.
bad/rater.rsl
good/rater.rsl

E-DATA-AS-CODE

A long list of values needs a file. A rater’s source holds rating logic, and its data lives in CSV files beside it. The check asks a list of more than 256 values to move out of the source and into a file. The limit applies to three forms: the members of an enum written in Types, the values of a membership test such as self in {…}, and the arms of a match. A list this long is data the filing publishes as a table or an appendix. In a CSV file it loads fast, a reviewer compares it with the filing row by row, and the rater stays short enough to read. Example The input class_code lists 257 eligible class codes inside the rater.
Fix Declare a number type with values: Csv and list the values in enums/ClassCode.csv, under a value column. The file takes the name of the type.
enums/ClassCode.csv
Other causes
  • An enum with more than 256 members gets inline enum `Territory` has 257 members. Declare Territory = Enum and list the members in enums/Territory.csv, or type an identifier such as a ZIP code as Code(pattern: "…").
  • A match with more than 256 arms gets match has 257 literal value arms. Move the rows to a table and read the result with lookup!.
bad/rater.rsl
good/enums/ClassCode.csv
good/rater.rsl

E-SELECT-TIE

A selection states how a tie breaks. argmax, argmin, topn, find and rank pick records from a list. Two records can tie: two locations with the same payroll both have the greatest score. The check asks the rater to state which record wins a tie. The list’s key decides: declare the list keyed by an input that names each record once, and the lowest key wins. One request then rates the same way however its list is ordered. Where the filing ranks tied records by a rule of its own, write that rule first, as then [cite: …]: priority. Example argmax picks the location with the greatest payroll, and the list locations lacks a key.
Fix Key the list by the input that numbers each location.
Other causes
  • A tie priority written as a plain last argument gets a tie priority is written `then`. Write then [cite: manual:p3]: l.hazard_factor.
  • A then priority on find gets a message that names argmax, argmin, topn and rank as the functions that take one.
bad/rater.rsl
good/rater.rsl

E-KEYED-ORDER

A keyed list is unordered. A list declared keyed by is a map from key to record. The key names each item, and the order of the request is free to change. index(self) and index(v) read the position of an item in its list. The check refuses them on a keyed list, so one request rates the same way however its list is ordered. Where a filing orders the items, state that order in the rater: as an input of the item, or with rank over a rating value. Example position_factor reads the position of a vehicle, and the list vehicles is keyed by number.
Fix Rank the vehicles by value, with the key as the tie break, and read the rank. The vehicle of the greatest value takes rank 0.
Other causes
  • = between two lists of keyed records gets `=` compares lists by position. Compare the items by key with all or exists, or compare the counts.
bad/rater.rsl
good/rater.rsl

E-UNION

A union arm holds inputs only. A union input such as experience: Rated | Unrated accepts one of several record types. Each request sends one arm, named by its tag, with that arm’s fields. The check asks each arm to be a record type that holds inputs and their refinements, each input a single value. The record that owns the union computes from the arm, inside a match that names every arm. Every calculation that depends on the arm then sits in one place, and the match shows what each arm contributes to the premium. Example The arm Rated computes capped_modifier in a step of its own.
Fix Move the calculation into the owner’s match, in the arm that binds Rated.
Other causes
  • A refinement on the union field gets union `experience` takes no metadata, annotations or refinements. Refine the arm record types.
  • A union that lists one arm twice gets union `experience` names arm `Rated` twice.
  • An arm that Records lacks gets union arm `Unrate` must be a record type.
  • An arm field named tag gets `tag` names the arm in the request. Give the field another name.
  • An arm field that holds a list or a record gets arm field `years` must be a number, Bool, Date, enum or Code, or an `Option` of one.
bad/rater.rsl
good/rater.rsl

E-UNION-USE

A union is read through a match. A union input such as experience: Rated | Unrated holds one of several record types. Each arm has its own fields, so a field such as modifier exists only when the request sends the Rated arm. The check asks every read of a union to be a match that names each arm. Inside an arm such as Rated(r), the name r reads that arm’s fields. Each field is then read only where it exists, and a new arm added later is reported by every match that omits it. Example The factor compares the union with an arm name in an if.
Fix Read the union with a match. The Rated arm binds its record as r and reads the modifier from it.
Other causes
  • An arm that reads a field its record lacks gets `r.modifer`: arm `Rated` has no such field; its fields are `modifier`.
  • A record refinement that reads an arm field as self.experience.modifier gets the same message for each arm that lacks the field.
  • A [key] after an arm field gets variant field `r.modifier` is not indexed.
bad/rater.rsl
good/rater.rsl

E-RECORD-ROOT

A rater has one top record. The records of a rater form one tree. A field typed with a record type, such as worksites: List(Worksite), places that record under the record that declares the field. The check asks for one record type that sits at the top, under which every other record hangs. That top record is the request: one policy, with its worksites inside it. One tree gives every value one place in a request. A record outside the tree stays empty in every request, so its inputs and calculations would be dead. Example The rater declares Worksite and leaves it outside Policy, so both sit at the top.
Fix Nest the record under the top record as a field, and read it from there. Delete a record that the rater has stopped using.
bad/rater.rsl
good/rater.rsl

E-RECORD-POSITION

Each record type sits at one field. A field typed with a record type places that record in the request tree. worksites: List(Worksite) puts every Worksite inside a Policy, in that list. The check asks each record type to be the type of one field. A record type then has one enclosing record and one path in a request, such as Policy.worksites[]. A calculation in the record relies on that place. It reads its enclosing record by type name, and the compiler counts its instances from the one field that holds it. Example Worksite types two fields of Policy: headquarters and worksites.
Fix Declare a record type for each field. Two record types that hold the same inputs share a type alias from Types for each input.
bad/rater.rsl
good/rater.rsl

E-RECORD-RECURSIVE

The record tree is finite. A field typed with a record type nests one record inside another. The check asks that nesting to end: a path down the fields passes each record type at most once. A record type that holds itself, directly or through other records, describes a request of unbounded depth. The compiler needs a finite tree to list every input, to prove each calculation and to state the cost of a rating. A record that sits under another record and also holds itself types two fields, so it gets E-RECORD-POSITION first. Example Policy holds its prior term as another Policy.
Fix Declare a separate record type with the inputs the nested record needs. A chain of similar records, such as layers, becomes a bounded list of one record type.
bad/rater.rsl
good/rater.rsl

E-REF-SCOPE

A reference points into a keyed list. A field typed Ref(Worksite) points at one record of a list in the same request. The request sends that record’s key: a placement names its worksite by number. The check asks for two things. The list of Worksite records is keyed by one of its inputs. The Ref field sits on a record below the one that holds the list. A key names each record of the list once, so every reference resolves to exactly one record. The rater then reads through it, as in self.worksite.hazard_factor. Example Placement refers to a Worksite, and the list worksites lacks a key.
Fix Key the list by the input that names each record once.
Other causes
  • A keyed by that names a field the record lacks gets `Worksite` has no such input `numbr`. The key is an input that holds a number, a Date, an enum member or a Code.
  • A keyed by on a field of another shape, such as one record, gets `worksites` is not a `List(R)` field.
  • A Ref on the record that holds the list gets the field must sit on a record that `Policy` encloses. Move the field to a record below it.
bad/rater.rsl
good/rater.rsl

E-ANCESTOR-READ

A type name reads an enclosing record. A calculation reads values in three directions. self.x reads its own record, a field reads a child, and a record type name reads a record that encloses this one. Inside Worksite, Policy.experience_modifier reads the one policy that holds the worksite. The check asks every read by type name to name such an enclosing record. A record lower in the tree, or beside this one, can occur many times in a request, so its type name matches several records. A list field and a fold, or a Ref field, say which records the calculation means. Example Policy reads Worksite.payroll, and a policy holds a list of worksites.
Fix Read the child records through the list field, and say how to combine them. Here the policy sums the payroll of its worksites.
Other causes
  • A read of the record’s own value by type name gets `Policy.payroll` names the record whose calculation this is. Read it as self.payroll.
  • A read of a record beside this one gets the message of the example. Add a Ref field that names the record, and read through it.
bad/rater.rsl
good/rater.rsl

E-INTERNAL

Report a compiler fault to Effective. E-INTERNAL reports a fault in the compiler itself. The compiler met a case that its rules leave out, and it stops with this code in place of a wrong answer. The message names what stopped it. Send the message to Effective with the rater that caused it, so the compiler gains a clear check message for that case. Meanwhile, look at the place the message names. A rater that gets this code often writes a form another way than RSL does, and the rewrite clears the message. Example sum adds two numbers here, and in RSL sum folds a list or an enum.
Fix Add two values with +. Keep sum for a list, as in sum(self.worksites as w, w.payroll).
Other causes
  • A file in enums/ saved in another encoding than UTF-8 gets enum CSV … is not UTF-8, together with E-ENUM-BACKING. Save the file as UTF-8.
  • A path in enums/ that the compiler fails to open gets failed to read enum CSV ….
bad/rater.rsl
good/rater.rsl