Skip to content
These are temporary community docs. The official docs are in progress.Help improve them
Markless
Esc
↑↓navigate↵open⌘Jpreview
On this page

Read a Markless error in four lines

Each Markless error names a code, says why, suggests a fix, and links to a page. A markless-allow comment silences one warning.

Last page, a test clicked a button. Sometimes the build stops before any test runs, with a long code in capital letters.

Markless refuses some code when it builds. It does not hand you a stack trace. It answers four questions: what broke, why, how to fix it, and where to read more.

Your editor shows type errors and syntax errors. Markless’s own rules run when the dev server or the build reads a .tsrx file. An error stops the build. A warning lets the build go on.

Press Build. Then fix the file and build again.

What does Markless tell you when it stops a build?

Press Build. Read the four parts of the error. Then press Add the key and build again.

The buildTry it
Terminalnot built yet

Nothing built yet.

Your code: List.tsrx
import { state } from '@markless/core'; export default function List() @{ let items = state(['a', 'b']); <ul> @for (const item of items) { <li>{item}</li> } </ul>}
What Markless did
Errors in the build0
  1. Nothing yet. Press Build.

Simplified. The code, the place, the fix, and the link come from a real build of this file. The “why” line is shortened. The full text is in the next section. The items are plain words, so each word is its own key.

Notice that the fix fits on one line. The error suggested it.

What the build prints

Here is a list with no key. The output below comes from a real compile of this file.

import { state } from '@markless/core';

export default function List() @{
	let items = state(['a', 'b']);

	<ul>
		@for (const item of items) {
			<li>{item}</li>
		}
	</ul>
}
MARKLESS_COMPILE_BLOCKED: List.tsrx has 1 compiler error(s).

MARKLESS_REPEAT_KEY_REQUIRED: @for (const item of items) repeats reactive state without a key. When items changes, the rows of this list have no identity to update, reorder, or resume by. (List.tsrx:7:3)
A keyed loop item keeps its state, events, and DOM attached to the same logical item across reorder, insert, and delete; without a key there is no stable identity root.
Add a stable domain key such as `@for (const item of items; key item.id)`, or key by position with `index i; key i` when state should follow the slot.
https://markless.dev/errors/MARKLESS_REPEAT_KEY_REQUIRED

Read each block top down: the code and the place, then why, then the first fix, then the link.

Silence a warning

If you accept a warning on purpose, write // markless-allow CODE: reason. Put it on the line above the warning, or on the same line.

<section>
	// markless-allow MARKLESS_REPEAT_KEY_IS_INDEX: static list, order never changes
	@for (const record of records; index slot; key slot) {
		<p>{record.label}</p>
	}
</section>

The comment has three rules. If you break one, you get a warning of its own.

Rule Code if you break it
Write a reason after the colon. MARKLESS_ALLOW_REASON_REQUIRED
You can’t silence an error. Fix it. MARKLESS_ALLOW_ERROR_UNSUPPRESSIBLE
If the warning no longer fires there, delete the comment. MARKLESS_ALLOW_STALE

Common codes

Every code starts with MARKLESS_. The table drops that start.

Code Kind What to do
FRAMEWORK_IMPORT_REQUIRED error Add import { state } from '@markless/core'.
STATE_MODULE_SCOPE error Move state() into the component body. For values many components share, use shared().
STATE_CREATION_SITE_UNSTABLE error Declare state() in the component body itself. Keep it out of branches, loops, handlers, and computed().
STATE_STALE_LOCAL_WRITE error A handler writes a plain let. Wrap its value in state().
REPEAT_KEY_REQUIRED error Add a key to the @for, like key item.id.
REPEAT_KEY_IS_INDEX warning Key by a stable field. Keep key i only if state belongs to the slot.
ASYNC_BOUNDARY_REQUIRED error Wrap the async read in @try with @pending and @catch.
ASYNC_POST_AWAIT_READ error Read the state before the first await.
STATE_WRITE_IN_COMPUTED error Move the write into an event handler.
EVENT_HANDLER_EMIT_UNSUPPORTED error The handler reads a plain local from the body. Use state, props, element handles, or imports instead.
TRY_BLOCK_TOGGLE_RERENDER warning An @if inside @try holds a component. Move the component out of the @if.
SHARED_FAMILY_SCOPE_IMPLICIT warning Pass { scope: 'widget' } or { scope: 'page' } to shared().
FRAMEWORK_API_RUNTIME_CALL error at run time Call state() and its friends only in .tsrx files.

The compiler has many more codes than this table shows.

You now have every tool an app author needs.

Next: Why does Markless insist on rules like a key for every list? Why Markless, technically →

Was this page helpful?