value
`. Use this when the tooltip is a flat property sheet without prose or conditional content. `path` is a dotted path against the item (e.g. `association.0.name`). Missing or empty values drop out silently rather than rendering an empty row. The value at `path` is coerced to string, HTML-escaped, and wrapped in `` at the leaf. There is no per-field render hook; when you need rich, interactive, or stateful tooltips (xref badges, evidence icons, taxonomy lookups, React components, …), own the overlay in the host instead — see [React host integration](/protvista/react-integration).
```yaml
tracks:
- id: compbias
label: Compositional bias
kind: features
filter: COMPBIAS
data: features
dataTooltip:
kind: fields
fields:
- { path: type, label: Type }
- { path: description, label: Description }
- { path: begin, label: Start }
- { path: end, label: End }
```
## `kind: markdown` form A full Markdoc template. Use this when the tooltip needs prose or conditional fragments. Field interpolation uses `{% $field %}`; flow control uses Markdoc’s `{% if %}` / `{% else %}` / `{% /if %}`.
```yaml
tracks:
- id: domain
label: Domain
kind: features
filter: DOMAIN
data: features
dataTooltip:
kind: markdown
template: |
### {% $description %}
**Position:** {% $begin %}–{% $end %}
{% if $score %}**Score:** {% $score %}{% /if %}
```
## Links from a field Markdoc cannot put a variable into an ordinary link’s destination, so a field that holds a URL — a `url` column in your own file, say — becomes a link with the `{% link %}` tag:
```yaml
dataTooltip:
kind: markdown
template: |
PMID {% $pmid %}: {% link href=$url %}read on PubMed{% /link %}
```
The self-closing form, `{% link href=$url /%}`, uses the URL itself as the link text. The URL goes through the same allowlist as every other link: only an absolute `http:` / `https:` / `mailto:` URL, or one starting with `/`, `#` or `?`, becomes a link. A value starting with `//` is protocol-relative, not root-relative: `//example.org/x` links to another site, as an `https:` URL would. Anything else — `javascript:`, a bare relative path like `docs/x.html`, or a feature whose `url` is empty or missing — renders the text alone, with no link. Links open in the same tab. ## Fields from your own file Any column of your own CSV or TSV file, or any key of your JSON records, is in scope as `$column` in a template and as a `path` in a `fields` list — not only the documented feature fields. See [Style and annotate each feature from your file](/protvista/your-data#style-and-annotate-each-feature-from-your-file). Name columns like identifiers (`gene_name`, `p-value`): a template cannot reference a name with a space in it, a `fields` path cannot reach one with a dot in it, and `$ctx` always means the tooltip context, never a column called `ctx`. ## When a field is missing A field a record does not have renders as nothing: in the `fields` form its row drops out, and in a template `{% $field %}` renders empty. That is expected when only some records carry the field (to drop the text around it too, see [Guard a field some records lack](#guard-a-field-some-records-lack)), and a record with none of the fields shows the default tooltip (see [A record with none of the fields](#a-record-with-none-of-the-fields)). When **no** record on the track carries it, the name is almost certainly wrong, so the viewer says so — once per track each time the data loads, naming every such field:
```plaintext
[protvista-uniprot] Track domains/hits: dataTooltip references unknown fields: pvalue, Gene
```
A row you add on its own, outside a group, is named by its track id alone (`Track hits: …`). The same text fires a `tooltip-field-miss` [`protvista-error` event](/protvista/troubleshooting#phases) with `severity: 'warning'` and the names in `context.fields`, and the playground lists it as a warning. The track itself renders as usual: there is no `⚠` badge and no alert panel, even with `strict` on. The names to check against are the record’s own: the fields a provider adapter outputs, or the column headers of your file (see [Fields from your own file](#fields-from-your-own-file)). A few details: * Every field the template names counts, including one inside `{% if $field %}`, a function such as `equals($field, "x")`, or `{% link href=$field %}`, and one in a fenced code block, which Markdoc fills in too. Inline code (single backticks) is printed literally, so a name there is not a reference. * A field that is present but empty (`''`, a blank cell, or `null` in a JSON key of your own) is not missing. The exceptions are a few built-in columns, which are left off a record that has no value for them, so a column with no value on any row reads as missing: * In a feature file, `description`, `score`, `color`, `shape`, `fill` and `opacity`: a blank CSV or TSV cell, or `null` in JSON. In JSON, `""` is left off too for `description` and the four render fields, but not for `score`: `"score": ""` is not a number, so it fails the track. * In a variation CSV or TSV file, `wildType`, `description` and `consequence`: a blank cell. * A variation file’s records carry `start` and `end` (not `position`), plus `variant` and `consequenceType`, and `wildType`, `description` and `consequence` when they have a value; its other columns are dropped. * For a dotted path such as `variant.wildType`, a record where `variant` is `null` counts as having it, so it does not warn. In the `fields` form that row just drops out. A template (`{% $variant.wildType %}`) currently fails the whole track on such a record, so guard it with `{% if $variant %}` or use the `fields` form. * `$ctx.accession`, `$ctx.trackId` and `$ctx.kind`, and any key you supply under the template’s `variables:`, are checked against those values rather than the records. * Only a `dataTooltip` you write is checked, and only one you write falls back to the default (below). A track using its kind’s built-in default, or the automatic tooltip, never warns, and neither do line-graph, coloured-sequence and heatmap tracks, which have no per-feature tooltip for `dataTooltip` to template (see [Line graphs](#line-graphs)). ### A record with none of the fields A record shows the track’s default tooltip instead of yours when both of these hold: * it has no value for any field the template names: each one is missing, `null`, or a blank cell (`''`); * what the template renders for it has no letter or digit: only punctuation, such as the `·` that `{% $gene %} · {% link href=$url /%}` leaves, or nothing at all. The default is what the track would show with no `dataTooltip`: its kind’s built-in tooltip (Type, Description, Start and End for `features`), or the automatic tooltip for a track with no `kind`. This is decided record by record, so on one track a record with a `url` shows your template and a record with neither field shows the default. It works the same in the `fields` form, where such a record would otherwise have no tooltip at all. Your template stays in charge whenever either condition fails: * A record with a value for at least one of the fields gets your template, whatever is left of it. * A template that has its own words for the case is kept: `{% if $gene %}{% $gene %}{% else /%}No gene recorded{% /if %}` shows “No gene recorded”, and `Lab hit {% $gene %}` shows “Lab hit”. * `$ctx.…` and keys you supply under `variables:` are not fields of the record, so a template that names only those never falls back. The fallback is silent. A field that no record on the track carries is still reported, as above. ### Guard a field some records lack To drop the text around a field that only some records have, wrap both in Markdoc’s built-in `{% if %}`:
```yaml
dataTooltip:
kind: markdown
template: |
{% if $gene %}{% $gene %} · {% /if %}{% link href=$url /%}
```
A record with both fields shows `HBA1 · https://…`, and one with a `url` but no `gene` (missing or `null`) shows the link alone. One with neither renders nothing, so it shows the default tooltip. A blank `gene` cell is different: see below. Markdoc’s `if` is false only for a missing field, `null` and `false`. A blank CSV or TSV cell is an empty string, which counts as true, so the template above still shows `·` before the link for a row whose `gene` cell is empty. To leave out blank cells too, test for them:
```yaml
dataTooltip:
kind: markdown
template: |
{% if and($gene, not(equals($gene, ""))) %}{% $gene %} · {% /if %}{% link href=$url /%}
```
## When to leave `dataTooltip` off For every track in the default config, no `dataTooltip` is set. Each semantic `kind` carries a sensible tooltip default — authors who just want the canonical UniProt look get it for free. Only set `dataTooltip` when you want a track-specific override, or when you’re authoring a track that doesn’t match an existing kind’s default. ## Line graphs A line graph has no per-feature datapoint to template, so `dataTooltip` does not apply to it. Clicking a line graph opens a fixed tooltip instead: the clicked position, then each series’ value there. *Licensed under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/).*
# Proteins outside UniProt
> You can use ProtVista without a UniProt accession by providing your own custom protein sequence—via a FASTA file, inline text, or raw residues—to visualize custom annotation tracks entirely independently of UniProt.
ProtVista normally starts from a UniProt accession: it fetches the entry’s sequence, then draws tracks against it. A predicted protein, a synthetic construct, a patient-specific variant or an unreviewed assembly has no accession — so give the viewer the sequence itself instead.
```yaml
sequence: ./my-protein.fasta
rows:
- id: hotspots
label: Hotspots on {accession}
kind: features
data: ./hotspots.csv
```
With `sequence:` set, the viewer draws the navigation, the sequence and every track that reads your own data. It makes **no request of its own**: no UniProt entry, no structure panel. The runnable [`examples/sequence-only/`](https://github.com/ebi-webcomponents/protvista/tree/next/examples/sequence-only) is exactly this config, with its FASTA file and data beside it. ## When to use it Use `sequence:` when the protein you want to annotate is not a UniProt entry, or when the viewer must not reach UniProt at all. If your protein *is* in UniProt, use `accession:` — you get the sequence, the structure panel and every UniProt track for free, and you can still [add your own tracks](/protvista/your-data). It suits a short protein too. The [small-peptide preset](/protvista/playground/#preset=small-peptide) shows Trp-cage, a designed 20-residue miniprotein, from its own sequence with its secondary structure from a CSV file. `accession:` and `sequence:` are alternatives: set one, never both. Pairing your own sequence with UniProt annotations would place UniProt’s coordinates on a sequence they don’t describe. ## Three ways to give the sequence **A FASTA file** — a path or URL to a file with one record:
```yaml
sequence: ./my-protein.fasta
```
The path is fetched relative to the hosting page, like a [data file](/protvista/your-data#a-path-gotcha-to-know), when the config loads. A bare name with a FASTA extension (`.fasta`, `.fa`, `.faa`, `.fas`) works too. **Inline FASTA** — written as a YAML literal block, with `|`:
```yaml
sequence: |
>my construct v2
MKTAYIAKQRQISFVKSHFSRQLEERLGLIEVQAPILSRVGDGTQDNLSGAEKAVQVKVKALPDAQ
```
Use `|`, not `>`. YAML’s folded `>` joins the lines into one, so the residues end up inside the header and the viewer reports that the sequence “has no residues”. The [own-sequence preset](/protvista/playground/#preset=own-sequence) is this form, with its track’s records written inline too, so it makes no request at all. Paste your own FASTA over the block, or load a `.fasta` file (below). **Raw residues** — just the letters:
```yaml
sequence: MKTAYIAKQRQISFVKSHFSRQLEERLGLIEVQAPILSRVGDGTQDNLSGAEKAVQVKVKALPDAQ
```
In every form, whitespace and line breaks are ignored, letters are uppercased, and one trailing `*` (a stop) is dropped. Residues are the one-letter codes A–Z. A FASTA file must hold exactly one record. The FASTA header is the protein’s name: the viewer shows it wherever it would show an accession — `{accession}` in a label, the “No feature data available for …” message, and warnings about your data. A header longer than 80 characters is cut short; with no header, the name is “your sequence”. ## Which tracks work Every track that reads your own data: * a file or URL of your own — CSV, TSV, JSON or BED, on any kind with a record shape (`features`, `linegraph`, `variants`, …); see [Load your own data](/protvista/your-data); * inline data written into the config; * a `from: custom` source filled by `setTrackData()`. A `kind: variants` track takes its residues from your `sequence:`, just as it takes them from the entry in accession mode. These need UniProt, and are rejected when the config loads: * any data URL that uses `{accession}` — including every source in the default UniProt config; * the AlphaFold and AlphaMissense kinds (`alphafold-confidence`, `alphamissense-pathogenicity`, `alphamissense-heatmap`), or an explicit `adapter:` that reads those feeds; * a label that *links* to an `{accession}` URL, such as `[AlphaFold](https://alphafold.ebi.ac.uk/entry/{accession})`. `{accession}` in plain label text is fine: it becomes your FASTA header. To show per-residue scores you computed yourself — pLDDT from your own structure prediction, say — use [`kind: linegraph`](/protvista/your-data#a-line-graph-of-your-own-values) with a `position,value` file. ## Start from a blank config `extends:` the default UniProt config won’t work: nearly every track in it needs UniProt. Write the rows you want from scratch. If a config does extend it, every inherited track that needs UniProt is listed, followed by a summary saying to start from a blank config instead. ## The error messages Every problem with a `sequence:` config is a config error. It shows in the viewer’s error panel, logs one console line, and fires a `protvista-error` event with `phase: 'config'`, `severity: 'error'` and each problem in `detail.issues` (see [Troubleshoot errors](/protvista/troubleshooting)): | `code` | Message | | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `accession-and-sequence` | `This config sets both 'accession:' and 'sequence:'. Use 'accession:' to show a UniProt entry, or 'sequence:' to show your own protein — not both.` When the accession comes from the element’s `accession` attribute, the message says so. | | `needs-accession` | `Track hotspots needs UniProt data: its data URL uses {accession}. With 'sequence:' only file, inline and custom sources work.` The reason may also be `kind 'alphafold-confidence' reads AlphaFold DB data for a UniProt entry` or `its label links to a UniProt-keyed URL ({accession})`. | | `invalid-sequence` | `./my-protein.fasta (parsed as FASTA): contains 2 records; the viewer shows one protein. …` — or an invalid character with its residue position, or no residues at all. An inline value that looks like a file name (`protein.txt`) is told to write it as `./protein.txt`. | | `cannot-resolve-sequence` | `Could not load the sequence file './my-protein.fasta': HTTP 404 Not Found.` | | `missing-protein` | `Nothing to show: set 'accession:' (a UniProt entry) or 'sequence:' (your own protein), or the element's accession attribute.` | The [playground](/protvista/playground/) checks a `sequence:` config as you type, inline sequence included, and disables its accession box while the config sets `sequence:`, itself or through an `extends:` base. ## Try your FASTA in the playground Press **Load data file…** in the [playground](/protvista/playground/) (or drop the file onto the config editor) and pick a one-record FASTA file: `.fasta`, `.fa`, `.faa` or `.fas`, or any other file whose first non-blank line starts with `>` (a `.csv`, `.tsv`, `.json` or `.bed` file is read as data, unless the config’s `sequence:` names it). It is read in your browser and never uploaded. Only its *name* goes into the config — `sequence: ./my-protein.fasta` — so neither the residues nor the header reach a link you share. If the config already names the file, as [`examples/sequence-only/`](https://github.com/ebi-webcomponents/protvista/tree/next/examples/sequence-only) does, it just loads — whatever its name, so a `seq.txt` of raw residues works too. Otherwise you choose where it goes: * **This config** sets its `sequence:` (replacing an inline one) and removes `accession:`, keeping your tracks. Tracks that need UniProt are then listed as `needs-accession` errors. * **A new sequence-only config** replaces the editor text with one that names only your file. Press Ctrl/Cmd+Z in the editor to get the old config back. A file the viewer would reject — two records, a character outside A–Z, no residues — is not loaded, and the playground shows the `invalid-sequence` message a hosted viewer would. A file over 2 MB, the most a hosted viewer fetches, is refused too. Someone who opens a shared link is asked to load the file themselves: until they do, the playground lists `local-file-missing`, and the preview pane, which shows no preview, says which file to load. If your header is a UniProt one (`>sp|P01542|…`), the protein is in UniProt: `accession: P01542` gives you its UniProt tracks as well. ## Your coordinates are still checked Rows that fall outside your sequence — a start below 1, or an end past the last residue — load and render as written, with a `track-data` warning on the console and the `protvista-error` event that names your FASTA header:
```plaintext
./hotspots.csv (parsed as CSV): 1 of 5 rows fall outside my construct v2 (240 residues); first: row 4, end 812. …
```
See [Common coordinate mistakes](/protvista/troubleshooting#common-coordinate-mistakes). ## Offline and air-gapped use With `sequence:` the viewer itself contacts no server: no UniProt, no AlphaFold, no structure lookups. The only requests are for the files your config names — the FASTA file and your data files, fetched relative to the page — so a page and its files on an internal server, or on disk behind a local web server, need no internet access. Inline sequence and inline data need no requests at all. For fully offline use, also host the viewer yourself rather than loading it from a CDN: serve the package’s `dist/` folder, which holds the component and the lazily loaded YAML parser chunk it fetches for a YAML config. ## Limits These are out of scope for `sequence:`: * isoforms; * more than one sequence in a viewer; * structures: no prediction, and no structure panel, for a custom sequence; * mapping your sequence to a UniProt entry automatically; * nucleotide sequences — residues are protein one-letter codes. *Licensed under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/).*
# Troubleshoot errors
> Explaining the 'protvista-error' event and what each detail and phase means, describing common problems and solutions.
When something doesn’t load, ProtVista tells you in three places: on screen (an alert panel or a ⚠ badge), in the browser console, and through a single `protvista-error` event you can listen for. This page covers all three, plus the most common causes. The full list of events the viewer dispatches, including `protvista-error`’s neighbours `protvista-event` and `protvista-layout-change`, is on the [Events](/protvista/events) page. Start with the messages on screen. If the whole viewer cannot load, read the alert panel. If only one track fails, check the ⚠ badge on that track. In the playground, also check the listed errors and warnings. These messages can help you identify the problem before using the browser console or writing an event listener. See [Where a failure shows up](#where-a-failure-shows-up) for details. ## The `protvista-error` event The element emits one bubbling `protvista-error` event for every problem, so a single listener covers all of them. Switch on `detail.phase`:
```js
const viewer = document.querySelector('protvista-uniprot');
viewer.addEventListener('protvista-error', (event) => {
const { phase, severity, message, source, context } = event.detail;
// `message` is the text the badge or panel shows, so the simplest useful
// listener is one line and needs no `switch` at all.
console.warn(`[protvista] ${phase}: ${message}`, source ?? '');
if (phase === 'config' && severity === 'error') {
console.error('The config was rejected:', event.detail.issues);
} else if (phase === 'track-fetch') {
// `trackId` is absent when a collapsed group's combined view failed.
const where = context.trackId
? `${context.groupId}/${context.trackId}`
: context.groupId;
console.warn(`Track ${where} failed`);
}
});
```
### `detail` | Field | What it holds | | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `phase` | Which part of the pipeline failed — see the table below. | | `severity` | `'error'` or `'warning'` — see [Where a failure shows up](#where-a-failure-shows-up). A warning names something that loaded, but not as written: a config warning, a `theme:` colour that could not be resolved, a component with no renderer. | | `message` | One line: the text the `⚠` badge or the alert panel shows, without the `[protvista]` tag the console line starts with. For a malformed file or a track that could not draw its data, this is what the decoder or the component threw, naming your file and the offending row. | | `source` | The URL or path the failure came from, when it had one. Absent for an inline, `custom` or `setTrackData()` source. | | `issues` | For `config`, the `ValidationIssue[]`. For `track-data` and `tooltip-field-miss`, one issue with `severity: 'warning'` whose `code` says what was found and whose `path` names the track. `[]` otherwise. | | `context` | Identifiers for the failure — see [The `context` object](#the-context-object). | ### Phases | `phase` | Fires when | Useful `context` | | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- | | `config` | The config fails to parse or validate, or it loads with warnings. `detail.severity` says which. `detail.issues` lists what’s wrong when the validator raised it, and a warning’s issue has `severity: 'warning'`; a warning raised after validation (an unresolvable `theme:` colour, a component with no renderer) has empty `issues`. | — | | `sequence` | No usable sequence was found for the accession. Never fires for a [`sequence:`](/protvista/sequence-only) config, which fetches no entry; a problem with its sequence is a `config` error. | `accession`, plus (on a fetch failure) `errorKind` / `status` / `url` | | `track-fetch` | A track’s data failed in a way that breaks it — a network error, a 5xx response, an unparseable body, a malformed file the decoder rejected, a 4xx on a path or URL to your own data, or a payload the track could not draw. A 4xx from a *provider endpoint* is treated as “missing, not broken” and does *not* fire this event. | `groupId`, `trackId`, `url`, `status`, `errorKind` | | `set-track-data` | Misuse of the `setTrackData()` programmatic API. | `groupId`, `trackId` | | `track-data` | A bring-your-own-data track loaded and renders as written, but something in its data is worth knowing: rows whose coordinates fall outside the protein’s sequence (the UniProt entry’s, or your `sequence:`) — a start below 1, or a position past the last residue — or, for a feature file, columns that were ignored (`tooltipContent`, `locations`, `residuesToHighlight`, names like `toString`), `shape` values that were ignored because they name a JavaScript built-in (`valueOf`, `constructor`, …), or `color` / `fill` values the canvas cannot paint. `detail.issues` holds one issue with `severity: 'warning'` and `code` set to `coordinate-out-of-range`, `data-field-ignored` or `unpaintable-color`. | `groupId`, `trackId`, `url` (file and URL tracks) | | `tooltip-field-miss` | A track’s authored `dataTooltip` references a field that none of the track’s records carries, so that part of every tooltip is blank. The track still renders. Fires once per track per load, listing every such field. `detail.issues` holds one issue with `code: 'tooltip-field-miss'` and `severity: 'warning'`. | `groupId`, `trackId`, `fields` | ### Where a failure shows up Every failure in the viewer — a config that won’t validate, a sequence that won’t load, a file that won’t parse — is described by two facts and routed by them: how **severe** it is, and whether it is scoped to the whole **viewer** or to one **track**. A row may also name a **phase**, and a phase row may be narrowed again by a **code** saying what was found: for `track-data`, the `code` of the event’s issue; on the viewer, a URL template left unfetched (`url-variable-unresolved`), a component with no renderer (`unrendered-component`) or a `theme:` colour that didn’t resolve (`theme-color-ignored`). The table below is the whole rule. It lives as data in `src/errors/router.ts` and is drift-tested against this page, so the two cannot disagree. | Severity | Scope | Phase | Code | Console | `protvista-error` | Alert panel | Row badge | Visitor notice | Author mode | | --------- | ------ | -------------------- | ------------------------- | ------- | ----------------- | -------------- | --------- | -------------- | ----------- | | `error` | viewer | any | any | yes | yes | always | — | no | yes | | `error` | track | any | any | yes | yes | under `strict` | yes | no | yes | | `warning` | viewer | `set-track-data` | any | yes | yes | under `strict` | — | no | yes | | `warning` | viewer | `config` | `unrendered-component` | yes | yes | never | — | viewer | yes | | `warning` | viewer | `config` | `theme-color-ignored` | yes | yes | never | — | no | yes | | `warning` | viewer | `track-fetch` | `url-variable-unresolved` | yes | yes | never | — | viewer | yes | | `warning` | viewer | any | any | yes | yes | never | — | no | yes | | `warning` | track | `track-data` | `coordinate-out-of-range` | yes | yes | never | no | track | yes | | `warning` | track | `track-data` | `unpaintable-color` | yes | yes | never | no | track | yes | | `warning` | track | `track-data` | `data-field-ignored` | yes | yes | never | no | no | yes | | `warning` | track | `track-data` | any | yes | yes | never | no | no | yes | | `warning` | track | `tooltip-field-miss` | any | yes | yes | never | no | no | yes | | `warning` | track | any | any | yes | yes | under `strict` | yes | no | yes | | `info` | viewer | any | any | yes | no | never | — | no | no | | `info` | track | any | any | yes | no | never | no | no | no | Reading it: * A **viewer-scoped error** leaves nothing to render past it — no config, or no sequence — so the panel replaces the viewer whether or not `strict` is set. * A **track-scoped** failure leaves the rest of the viewer working, so the row carries it as a `⚠` badge. `strict` promotes the batch to a single aggregated panel; without `strict` the badges stand alone. * A **viewer-scoped warning** names something legal that loaded as written — a config warning, or a `theme:` field that could not be resolved. It never raises the panel, even under `strict`: hiding a working viewer behind a notice about something that worked is not a louder failure, just a less useful one. Two of them change what is on screen, so they also carry a **visitor notice** on the viewer: a track whose data URL was never fetched (an undefined `{variable}`), and a component with no renderer. A `theme:` colour that didn’t resolve leaves the default colours in place and nothing missing, so it has none. * The one exception is a rejected **`setTrackData()`** call, which `strict` does promote. The rows above are read most-specific-first, so a row naming a `phase` wins over the `any` row for the same severity and scope. A config warning describes something that happened as written; an ignored API call describes something the caller asked for that did not happen, which is what `strict` exists to make loud. * A **`track-data`** warning — rows whose coordinates fall outside the sequence, a column of your file that was ignored, a colour the canvas cannot paint — goes the other way for a track. The rows loaded and render as written, so it takes neither the `⚠` badge nor the panel: a badge would mark a working row as broken. Where the visitor would otherwise be misled — features not drawn in full, colours not painted — the track gets a quieter **visitor notice** instead. An ignored column changes nothing drawn, so it has none. * A **`tooltip-field-miss`** warning is the same for the same reason: every record renders, and only the track’s tooltip template names a field the data never has. No badge and no panel; the event and the console line carry it. * **`info`** is an expected absence, not a failure: a provider endpoint answering 404 for an entity with no data of this kind, or a `from: custom` track nobody injected data into. It gets a console line and no user surface. * **Author mode** lists everything the `protvista-error` event carries — every error and every warning, never `info` — so its column is the event’s. See [What visitors and authors see](#what-visitors-and-authors-see). A **Retry** control appears on whichever surface carried the failure, and only when retrying could plausibly change the answer: a network error or a 5xx may be transient, and a path or URL to your own data that 404s is something *you* can fix — correct it or drop the file into place, then Retry reloads that one track instead of the whole page. A built-in provider adapter that throws gets a Retry too: some make requests of their own (the AlphaFold confidence and AlphaMissense tracks each fetch a second file), so their failures can be as temporary as a 5xx. A malformed file, a malformed `setTrackData()` payload, an unregistered adapter name and a payload the track could not draw all get no Retry: they would fail the same way again with no action available in between. ### What visitors and authors see The console and the `protvista-error` event reach you; a visitor to a page that embeds the viewer sees neither. So the viewer follows one rule: **tell visitors when what they’re looking at is incomplete or misleading, and tell authors everything.** **Visitor notices.** A warning whose row in the table above has a visitor notice puts a quiet ⓘ on the affected track’s label. It opens a short, plain-language note — “2 features extend beyond this sequence, so they aren’t shown in full.”, “Some colours in the data couldn’t be shown, so some features may be in the wrong colour.” — that never names a file, a URL, a field or a variable. A viewer-level notice (““Partner data” isn’t shown: its data couldn’t be loaded.”, ““Mine” can’t be displayed in this viewer.”) goes on an ⓘ in the top bar, beside **Customize**. So does a track notice whose label isn’t on screen — a track inside a collapsed group, a track with no data to draw, a customize-mode placeholder, or the “No feature data available” view — prefixed with the track’s name. A track you hid from the layout tells visitors nothing until Customize shows it again. The notes are announced once to screen readers, politely, and the ⓘ is a keyboard-reachable button: Escape, a click elsewhere or moving focus on closes its note. A note too long for the room beside its button scrolls. Visitor notices are on by default. The **`quiet-notices`** attribute turns them off:
```html