Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Errors: schema types and keys

These errors come from the types, the keys, and the counts that a schema declares. Sections 3, 4, and 5 of the core specification define them. One error, TL_33, reports a problem in a document: a key that breaks one of the schema’s key derivations.

TL_29

A type under types reuses the name of a built-in type (TL_29).

Message

<file>:<line>: error[TL_29]: type `<name>` is built in and reserved; name the type otherwise

Cause

tramlines reserves the names of the built-in types text, word, int, slug, and seq, so a schema can’t define them again.

Fix

Change the schema. Remove the type and use the built-in one, or give the type another name and use that name in each template.

Example

This schema defines a type int, which is built in:

note.yaml

line-limit: 0
types:
  int: '[0-9]+'
sections:
  - heading: Note
    level: 1
    blocks:
      - kind: bullet-list
        each:
          template: '${:int} ${}'
          example: 2 apples

note.md

# Note

- 2 apples
$ tramlines validate --schema note.yaml note.md
note.yaml:3: error[TL_29]: type `int` is built in and reserved; name the type otherwise
1 error, 0 warnings
[exit 1]

Remove the type, and use the built-in int:

note.yaml

line-limit: 0
sections:
  - heading: Note
    level: 1
    blocks:
      - kind: bullet-list
        each:
          template: '${:int} ${}'
          example: 2 apples
$ tramlines validate --schema note.yaml note.md
0 errors, 0 warnings

TL_109

The regular expression of a type under types contains an anchor or a capture group (TL_109).

Message

<file>:<line>: error[TL_109]: type `<name>`: `<regex>` holds an anchor; a template matches the whole line itself
<file>:<line>: error[TL_109]: type `<name>`: `<regex>` holds a capture group; write `(?:…)`, since a template names its own groups

Cause

The regular expression of a type matches one hole of a template. The template anchors the whole line and names its own groups, so the type can’t contain a ^ or $ anchor or a capture group. The command reports each refused type once. No template that names a refused type reports TL_120.

Fix

Change the schema. Remove the anchors from the regular expression of the type, and write each group as (?:…).

Example

The type code of this schema starts with ^ and ends with $:

note.yaml

line-limit: 0
types:
  code: '^[A-Z]+$'
sections:
  - heading: Note
    level: 1
    blocks:
      - kind: bullet-list
        each:
          template: '${:code} ${}'
          example: SHOP milk

note.md

# Note

- SHOP milk
$ tramlines validate --schema note.yaml note.md
note.yaml:3: error[TL_109]: type `code`: `^[A-Z]+$` holds an anchor; a template matches the whole line itself
1 error, 0 warnings
[exit 1]

Remove the anchors:

note.yaml

line-limit: 0
types:
  code: '[A-Z]+'
sections:
  - heading: Note
    level: 1
    blocks:
      - kind: bullet-list
        each:
          template: '${:code} ${}'
          example: SHOP milk
$ tramlines validate --schema note.yaml note.md
0 errors, 0 warnings

TL_31

The key of a rule or a format names no hole or named group of its shape (TL_31).

Message

<file>:<line>: error[TL_31]: `key` `<key>` names no hole or named group of the rule's shape
<file>:<line>: error[TL_31]: `key` `<key>` names a hole of a shape, and the rule declares none
<file>:<line>: error[TL_31]: format `<format>`: `key` `<key>` names no hole or named group of the shape
<file>:<line>: error[TL_31]: format `<format>`: `key` `<key>` names no hole or named group of variant `<variant>`

Cause

The key key holds the name of a hole of the template, such as item in ${item:slug}, or of a named group of the pattern. The rule captures the key from that hole. When key names something else, or when the rule declares no shape, the rule finds no hole to read the key from. The key of a format names a hole or a named group of the shape of the format, and of each of its variants.

Fix

Change the schema. Set key to the name of a hole or a named group of the shape, or give the rule the shape that holds the key.

Example

This rule names its key name, but its template calls the hole item:

note.yaml

line-limit: 0
sections:
  - heading: Note
    level: 1
    blocks:
      - kind: bullet-list
        each:
          template: '${item:slug}: ${:int}'
          key: name
          example: 'milk: 2'

note.md

# Note

- <a id="milk"></a>milk: 2
$ tramlines validate --schema note.yaml note.md
note.yaml:8: error[TL_31]: `key` `name` names no hole or named group of the rule's shape
1 error, 0 warnings
[exit 1]

Name the hole:

note.yaml

line-limit: 0
sections:
  - heading: Note
    level: 1
    blocks:
      - kind: bullet-list
        each:
          template: '${item:slug}: ${:int}'
          key: item
          example: 'milk: 2'
$ tramlines validate --schema note.yaml note.md
0 errors, 0 warnings

TL_113

A rule declares key and binds a format that captures a key itself (TL_113).

Message

<file>:<line>: error[TL_113]: `key` beside format `<format>`, which captures a key itself

Cause

A format that declares key captures that key from every line that it matches. A rule that binds the format takes the key of the format, so a key of its own would name a second key for the same line.

Fix

Change the schema. Remove key from the rule, or bind a format that declares no key.

Example

The format item captures the key id, and the rule that binds it declares key too:

note.yaml

line-limit: 0
formats:
  item:
    template: '${id:slug}: ${:int}'
    key: id
    example: 'milk: 2'
sections:
  - heading: Note
    level: 1
    blocks:
      - kind: bullet-list
        each:
          format: item
          key: id

note.md

# Note

- <a id="milk"></a>milk: 2
$ tramlines validate --schema note.yaml note.md
note.yaml:13: error[TL_113]: `key` beside format `item`, which captures a key itself
1 error, 0 warnings
[exit 1]

Remove key from the rule:

note.yaml

line-limit: 0
formats:
  item:
    template: '${id:slug}: ${:int}'
    key: id
    example: 'milk: 2'
sections:
  - heading: Note
    level: 1
    blocks:
      - kind: bullet-list
        each:
          format: item
$ tramlines validate --schema note.yaml note.md
0 errors, 0 warnings

TL_33

A key in the document starts with a prefix that the key-derives-from of its rule doesn’t allow, or the key lacks the separator (TL_33).

Message

<file>:<line>: error[TL_33]: key `<key>` derives from `<prefix>`, which rule `<rule-id>` did not capture (schema <id>, <place of the rule>)
<file>:<line>: error[TL_33]: key `<key>` derives from `<prefix>`, which is not `<value>`, the value of the frontmatter `<frontmatter key>` (schema <id>, <place of the rule>)
<file>:<line>: error[TL_33]: key `<key>` derives from `<prefix>`, and the frontmatter `<frontmatter key>` that it derives from is absent (schema <id>, <place of the rule>)
<file>:<line>: error[TL_33]: key `<key>` has no `<separator>` separator to derive from (schema <id>, <place of the rule>)

Cause

key-derives-from: { rule: <rule-id>, separator: <separator> } requires the part of each key before the separator to be a key that the named rule captured. key-derives-from: { from: <frontmatter key>, separator: <separator> } requires it to be the value of that frontmatter key. The message shows that value after the frontmatter key’s name. The error means that a key in the document starts with another prefix, or contains no separator at all.

Fix

Change the key in the document so that its prefix is a key of the named rule or the frontmatter value. If the schema names the wrong rule, frontmatter key, or separator, fix key-derives-from in the schema instead.

Example

This schema requires the key of each item to start with the value of the frontmatter key code:

note.yaml

line-limit: 0
types:
  item-id: '[A-Z]+-[0-9]+'
frontmatter:
  code:
    pattern: '[A-Z]+'
    example: SHOP
sections:
  - heading: Note
    level: 1
    blocks:
      - kind: bullet-list
        each:
          template: '${id:item-id}: ${}'
          key: id
          key-derives-from: { from: code, separator: "-" }
          example: 'SHOP-1: milk'

The second item of this document starts with HOME:

note.md

---
code: SHOP
---

# Note

- <a id="shop-1"></a>SHOP-1: milk
- <a id="home-2"></a>HOME-2: soap
$ tramlines validate --schema note.yaml note.md
note.md:8: error[TL_33]: key `HOME-2` derives from `HOME`, which is not `SHOP`, the value of the frontmatter `code` (schema note, section "Note")
1 error, 0 warnings
[exit 1]

Start the key with the code:

note.md

---
code: SHOP
---

# Note

- <a id="shop-1"></a>SHOP-1: milk
- <a id="shop-2"></a>SHOP-2: soap
$ tramlines validate --schema note.yaml note.md
0 errors, 0 warnings

TL_96

A unit rule that captures no key declares key-derives-from (TL_96).

Message

<file>:<line>: error[TL_96]: `key-derives-from` on a rule that captures no key

Cause

key-derives-from checks the key that its rule captures against a frontmatter value or against the keys of another rule. The rule declares no key, and it binds either no format or a format that declares none. It therefore captures no key for key-derives-from to check. On a heading, a key-derives-from with no key reports TL_103 instead, because the grammar requires key beside it.

Fix

Change the schema. Give the rule a key that names a hole of its shape, or remove key-derives-from.

Example

This rule derives its keys from the frontmatter key code, but declares no key:

note.yaml

line-limit: 0
types:
  item-id: '[A-Z]+-[0-9]+'
frontmatter:
  code:
    pattern: '[A-Z]+'
    example: SHOP
sections:
  - heading: Note
    level: 1
    blocks:
      - kind: bullet-list
        each:
          template: '${id:item-id}: ${}'
          key-derives-from: { from: code, separator: "-" }
          example: 'SHOP-1: milk'

note.md

---
code: SHOP
---

# Note

- <a id="shop-1"></a>SHOP-1: milk
$ tramlines validate --schema note.yaml note.md
note.yaml:14: error[TL_96]: `key-derives-from` on a rule that captures no key
1 error, 0 warnings
[exit 1]

Declare the key:

note.yaml

line-limit: 0
types:
  item-id: '[A-Z]+-[0-9]+'
frontmatter:
  code:
    pattern: '[A-Z]+'
    example: SHOP
sections:
  - heading: Note
    level: 1
    blocks:
      - kind: bullet-list
        each:
          template: '${id:item-id}: ${}'
          key: id
          key-derives-from: { from: code, separator: "-" }
          example: 'SHOP-1: milk'
$ tramlines validate --schema note.yaml note.md
0 errors, 0 warnings

TL_117

A key-derives-from names a rule or a frontmatter key that the schema doesn’t declare (TL_117).

Message

<file>:<line>: error[TL_117]: `key-derives-from` names no rule `<rule-id>`
<file>:<line>: error[TL_117]: `key-derives-from` names no frontmatter key `<key>`

Cause

key-derives-from: { rule: <rule-id>, separator: <separator> } checks each key against the keys of the rule with that rule-id. key-derives-from: { from: <frontmatter key>, separator: <separator> } checks it against the value of that frontmatter key. The schema declares no rule or frontmatter key of that name.

Fix

Change the schema. Correct the name in key-derives-from, or declare the rule or the frontmatter key that it names.

Example

This rule derives its keys from a frontmatter key code, which the schema doesn’t declare:

note.yaml

line-limit: 0
types:
  item-id: '[A-Z]+-[0-9]+'
sections:
  - heading: Note
    level: 1
    blocks:
      - kind: bullet-list
        each:
          template: '${id:item-id}: ${}'
          key: id
          key-derives-from: { from: code, separator: "-" }
          example: 'SHOP-1: milk'

note.md

---
code: SHOP
---

# Note

- <a id="shop-1"></a>SHOP-1: milk
$ tramlines validate --schema note.yaml note.md
note.yaml:10: error[TL_117]: `key-derives-from` names no frontmatter key `code`
1 error, 0 warnings
[exit 1]

Declare code:

note.yaml

line-limit: 0
types:
  item-id: '[A-Z]+-[0-9]+'
frontmatter:
  code:
    pattern: '[A-Z]+'
    example: SHOP
sections:
  - heading: Note
    level: 1
    blocks:
      - kind: bullet-list
        each:
          template: '${id:item-id}: ${}'
          key: id
          key-derives-from: { from: code, separator: "-" }
          example: 'SHOP-1: milk'
$ tramlines validate --schema note.yaml note.md
0 errors, 0 warnings

TL_47

A rule sets key-optional but captures no key (TL_47).

Message

<file>:<line>: error[TL_47]: `key-optional` without a `key` or a `format` that declares one

Cause

key-optional: true lets a unit leave out the key that its rule captures. The rule declares no key and binds no format that declares one. The rule therefore captures no key that a unit could leave out.

Fix

Change the schema. Remove key-optional, or declare the key that it makes optional.

Example

This rule sets key-optional and captures no key:

note.yaml

line-limit: 0
sections:
  - heading: Note
    level: 1
    blocks:
      - kind: bullet-list
        each:
          template: '${:slug}'
          key-optional: true
          example: milk

note.md

# Note

- milk
$ tramlines validate --schema note.yaml note.md
note.yaml:8: error[TL_47]: `key-optional` without a `key` or a `format` that declares one
1 error, 0 warnings
[exit 1]

Remove key-optional:

note.yaml

line-limit: 0
sections:
  - heading: Note
    level: 1
    blocks:
      - kind: bullet-list
        each:
          template: '${:slug}'
          example: milk
$ tramlines validate --schema note.yaml note.md
0 errors, 0 warnings

TL_98

A rule or a frontmatter key declares a min greater than its max (TL_98).

Message

<file>:<line>: error[TL_98]: `min` <min> is above `max` <max>

Cause

min and max bound how many units a block or a rule takes or counts, or how many elements a frontmatter list contains. When min is larger than max, no count meets both bounds. No document can then satisfy the rule.

Fix

Change the schema. Swap the two numbers, or correct the one that’s wrong.

Example

This rule requires at least two items and allows at most one:

note.yaml

line-limit: 0
sections:
  - heading: Note
    level: 1
    blocks:
      - kind: bullet-list
        rules:
          - template: '${:slug}'
            min: 2
            max: 1
            example: milk

note.md

# Note

- milk
$ tramlines validate --schema note.yaml note.md
note.yaml:8: error[TL_98]: `min` 2 is above `max` 1
1 error, 0 warnings
[exit 1]

Set min to a value no higher than max:

note.yaml

line-limit: 0
sections:
  - heading: Note
    level: 1
    blocks:
      - kind: bullet-list
        rules:
          - template: '${:slug}'
            min: 1
            max: 2
            example: milk
$ tramlines validate --schema note.yaml note.md
0 errors, 0 warnings