Lint rules
This appendix lists all lint rules that bino lint and bino build apply to your report manifests.
Lint rules check the content of your documents (semantic/business rules), while schema validation checks the structure.
Most lint findings are treated as warnings and do not block builds. However, some rules produce errors that will cause the build to fail (marked with severity below).
| ID | Name | Severity | Description |
|---|---|---|---|
report-artefact-required | Report Artefact Required | Warning | At least one ReportArtefact document must be defined. |
artefact-layoutpage-required | Artefact LayoutPage Required | Warning | Each ReportArtefact must have at least one LayoutPage that matches its constraints and format. |
text-content-required | Text Content Required | Warning | Text components must have a non-empty spec.value field. |
dataset-required | Dataset Required | Warning | Table, ChartStructure, ChartTime, ChartScatter, ChartBubble, and ChartBullet components must have a spec.dataset binding. |
table-sum-title-unused | Table Sum Title Unused | Warning | spec.sumTitle only labels the grand-total row of type: sum / type: opt tables. |
missing-required-reference | Missing Required Reference | Error | Required child references (ref) must point to existing documents. |
page-layout-slots-used | Page Layout Slots Used | Warning | LayoutPage children count must match the expected slots for its pageLayout. |
card-layout-slots-used | Card Layout Slots Used | Warning | LayoutCard children count must match the expected slots for its cardLayout. |
asset-reference-undefined | Asset Reference Undefined | Warning | Image references must name a declared Asset document or a reachable URL. |
asset-source-missing | Asset Source Missing | Warning | An Asset's spec.source.localPath must point at an existing file. |
inline-ref-bounds | Inline Reference Bounds | Warning | @inline(N) references must have valid indices within the dependencies array. |
dataset-source-exclusive | DataSet Source Exclusive | Warning | The source field is mutually exclusive with query and prql in DataSet specs. |
inline-naming-conflict | Inline Naming Conflict | Warning | Document names must not start with _inline_ as this prefix is reserved. |
Rule details
Section titled “Rule details”report-artefact-required
Section titled “report-artefact-required”Every bino report project needs at least one ReportArtefact document to define what PDF(s) to generate.
Example fix: Add a ReportArtefact manifest to your project:
apiVersion: bino.bi/v1
kind: ReportArtefact
metadata:
name: my-report
spec:
title: Monthly Sales Reportartefact-layoutpage-required
Section titled “artefact-layoutpage-required”Each ReportArtefact must have at least one LayoutPage that:
- Passes constraints — The page's
metadata.constraintsmust match the artefact's context (labels, spec, or mode). The linter checks bothbuildandpreviewmodes; a page is valid if it matches in either mode. - Matches format — The page's
spec.pageFormatmust match the artefact'sspec.format. Both default toxgaif not specified.
Example problem:
# Artefact with format: a4
kind: ReportArtefact
metadata:
name: print-report
spec:
format: a4
---
# Page with default format (xga) won't match!
kind: LayoutPage
metadata:
name: page1
spec:
children: [...]Fix: Set spec.pageFormat: a4 on the LayoutPage.
text-content-required
Section titled “text-content-required”Text components are meant to display content. An empty spec.value produces blank output.
Example problem:
kind: Text
metadata:
name: header
spec:
value: "" # Empty!Fix: Provide meaningful content in spec.value.
dataset-required
Section titled “dataset-required”Data visualization components (Table, ChartStructure, ChartTime, ChartScatter, ChartBubble, ChartBullet) need a dataset to display. Without spec.dataset, there's nothing to render.
Example problem:
kind: Table
metadata:
name: sales-table
spec:
# Missing dataset!Fix: Add a dataset reference:
spec:
dataset: sales-dataOr multiple datasets for charts:
spec:
dataset:
- revenue
- coststable-sum-title-unused
Section titled “table-sum-title-unused”spec.sumTitle labels the grand-total row at the bottom of a table. That row only exists for type: sum and type: opt. On type: list (the default), type: sumnototal and type: optnototal no total row is generated, so the label is silently dropped.
Example problem:
kind: Table
metadata:
name: sales-table
spec:
dataset: sales-data
type: list # renders no total row …
sumTitle: Total # … so this label is never shownFix: render a total row, or drop the label.
# Render the grand-total row and label it
spec:
dataset: sales-data
type: sum
sumTitle: Total # leave empty to use the IBCS ❖ symbolThe rule also covers tables defined inline in LayoutPage, LayoutCard and Grid children, and in Tree nodes. A child that inherits its type from a referenced Table via ref is checked against the effective type, so overriding only sumTitle on a type: sum component does not warn.
missing-required-reference
Section titled “missing-required-reference”Child references (ref) in LayoutPage and LayoutCard must point to documents that exist. This rule catches typos, missing files, and broken references early.
Severity: Error (blocks build)
Example problem:
kind: LayoutPage
metadata:
name: dashboard
spec:
pageLayout: 2x2
children:
- kind: ChartTime
ref: revnue_chart # Typo! Should be "revenue_chart"Error message:
required reference "revnue_chart" of kind "ChartTime" not found (use optional: true to allow missing refs)Fixes:
-
Correct the typo — Fix the reference name to match the target document's
metadata.name. -
Create the missing document — Add the referenced manifest to your project.
-
Mark as optional — If the reference is legitimately optional (e.g., debug-only component), add
optional: true:
children:
- kind: ChartTime
ref: debug_chart
optional: true # Won't error if missingNote: References that exist but are filtered out by constraints (e.g., mode == "preview") do not trigger this error. Only genuinely missing references cause failures.
See also: Optional references
page-layout-slots-used
Section titled “page-layout-slots-used”Each LayoutPage must have exactly the number of children that match its pageLayout slot count. This rule is evaluated per artefact, counting only children that:
- Pass constraints — Children with
metadata.constraintsmust match the artefact's context. - Have valid refs — Children with
refmust point to an existing document (or be markedoptional: true). Missing required refs trigger themissing-required-referenceerror. Optional refs that are missing don't count as slots. - Are renderable — Children must have either a
refor inlinespec.
Slot counts for predefined layouts:
| Layout | Slots |
|---|---|
full | 1 |
split-horizontal | 2 |
split-vertical | 2 |
2x2 | 4 |
3x3 | 9 |
4x4 | 16 |
1-over-2 | 3 |
1-over-3 | 4 |
2-over-1 | 3 |
3-over-1 | 4 |
For custom-template, the slot count is the number of distinct named area tokens in pageCustomTemplate:
# 3 slots: a, b, c
pageLayout: custom-template
pageCustomTemplate: |
"a a"
"b c"
# 2 slots: aa, bb
pageLayout: custom-template
pageCustomTemplate: |
"aa aa"
"bb bb"Example problem:
kind: LayoutPage
metadata:
name: dashboard
spec:
pageLayout: 2x2 # Expects 4 children
children:
- kind: Text
spec: { value: "Hello" }
- kind: Table
ref: sales-table
# Only 2 children, but 2x2 expects 4!Fix: Add children to fill all slots, or change pageLayout to match actual children count.
card-layout-slots-used
Section titled “card-layout-slots-used”Same as page-layout-slots-used, but for LayoutCard components. Each card's cardLayout defines how many children it expects.
Example problem:
kind: LayoutCard
metadata:
name: summary-card
spec:
cardLayout: split-horizontal # Expects 2 children
children:
- kind: Text
spec: { value: "Only one child" }Fix: Add a second child or change cardLayout: full.
asset-reference-undefined
Section titled “asset-reference-undefined”Images are referenced by the name of an Asset document, not by file path. This rule checks every image reference and warns when it cannot resolve, which otherwise fails silently: the name is passed through to the browser as if it were a URL, and you get a broken image with no error.
It covers messageImage (LayoutPage), titleImage (LayoutCard), source (Image) — including components defined inline in children or nodes — and asset: image references inside Markdown (messageText, titleBusinessUnit, and a Text component's value).
Example problem:
kind: LayoutPage
metadata:
name: dashboard
spec:
pageLayout: full
messageImage: logo # No Asset document is named "logo"
messageText: "Report by  " # Typo! Should be "company"Fix: declare the Asset and reference it by its metadata.name.
apiVersion: bino.bi/v1alpha1
kind: Asset
metadata:
name: logo
spec:
type: image
mediaType: image/png
source:
localPath: images/logo.png # Relative to this manifestA reference resolves when it is one of:
- the
metadata.nameof anAssetdocument (messageImage: logo), optionally with theasset:prefix (messageImage: asset:logo); - an absolute URL or data URI the browser can fetch (
https://…,data:image/png;base64,…).
A value that looks like a file path (images/logo.png) is checked against the filesystem, relative to the manifest, and warns when the file is absent. Note that bino serves only declared Assets — a bare path is not served even when the file exists, so prefer declaring an Asset.
Font Assets do not count: they are not available to image references.
See also: Asset
asset-source-missing
Section titled “asset-source-missing”An Asset whose spec.source.localPath points at a file that is not on disk. The path is resolved relative to the manifest that declares it, the same way the renderer resolves it.
This is a build error at render time; the rule surfaces it while you are still editing, instead of at the next build.
Example problem:
kind: Asset
metadata:
name: logo
spec:
type: image
mediaType: image/png
source:
localPath: images/logo.png # File was moved or deletedFix: restore the file, or correct localPath. Assets sourced from remoteURL or inlineBase64 are not checked.
See also: Asset
inline-ref-bounds
Section titled “inline-ref-bounds”When using inline DataSource definitions in a DataSet's dependencies, the @inline(N) references in queries must point to valid indices.
Example problem:
kind: DataSet
metadata:
name: my_dataset
spec:
dependencies:
- type: csv
path: ./data/sales.csv
query: |
SELECT * FROM @inline(5) # Index 5 doesn't exist!Error message:
@inline(5) out of bounds (have 1 inline dependencies)Fix: Use @inline(0) to reference the first (and only) inline dependency.
See also: Inline DataSet definitions
dataset-source-exclusive
Section titled “dataset-source-exclusive”The source field in DataSet provides direct pass-through to a DataSource without transformation. It cannot be used together with query or prql.
Example problem:
kind: DataSet
metadata:
name: conflicting_dataset
spec:
source: sales_csv
query: | # Can't have both source and query!
SELECT * FROM sales_csvFix: Choose one approach:
# Option 1: Use source for pass-through
spec:
source: sales_csv
# Option 2: Use query for transformation
spec:
query: SELECT * FROM sales_csv
dependencies:
- sales_csvSee also: Direct source pass-through
inline-naming-conflict
Section titled “inline-naming-conflict”Document names starting with _inline_ are reserved for generated inline definitions. User-defined documents must not use this prefix.
Example problem:
kind: DataSource
metadata:
name: _inline_my_data # Reserved prefix!
spec:
type: csv
path: ./data.csvFix: Choose a different name that doesn't start with _inline_:
metadata:
name: my_dataAdding custom rules
Section titled “Adding custom rules”The bino linter is designed for easy rule addition. Each rule has:
- ID: A unique identifier (e.g.,
naming-lowercase,reference-undefined-dataset). - Name: A short human-readable name.
- Description: An explanation of what the rule checks.
- Check function: The logic that inspects documents and returns findings.
Rules are registered in internal/report/lint/rules.go.
Suppressing warnings
Section titled “Suppressing warnings”Currently, lint warnings cannot be suppressed. Future versions may add per-rule or per-file suppression.
See also
Section titled “See also”- bino lint – CLI command for running lint.
- bino build – build command (runs lint by default).