Skip to content

Error Codes

Avenx-JS uses structured error codes starting with AVX_C for compiler errors and AVX_R for runtime issues.

Every runtime error code in this guide (e.g. AVX_R01) is ultimately thrown as an instance of AvenxError, a custom error class exported from the framework’s runtime module. It extends the native Error and pairs a structured code with a formatted, human-readable message. Understanding this class is useful if you’re writing custom guards, components, or services and want to throw or catch framework-consistent errors yourself.

new AvenxError(code, ...args)
Parameter Type Description
code string One of the AvenxErrorCodes identifiers (e.g. 'AVX_R01'). Selects which message template is used.
...args any[] Values substituted into the message template’s {0}, {1}, etc. placeholders, in order.
Property Type Description
code string The raw error code passed to the constructor (e.g. 'AVX_R01').
message string The fully formatted message, prefixed with the code, e.g. [AVX_R01] Mount target selector "#app" was not found in the DOM.
name string Always 'AvenxError'. Useful for distinguishing it from other Error subclasses in a catch block.
import { AvenxError, AvenxErrorCodes } from 'avenx-js';
import { AvenxError, AvenxErrorCodes } from 'avenx-js';
function mount(selector) {
const target = document.querySelector(selector);
if (!target) {
throw new AvenxError(AvenxErrorCodes.MOUNT_TARGET_NOT_FOUND, selector);
}
// ...
}
import { AvenxError, AvenxErrorCodes } from 'avenx-js';
try {
mount('#app');
} catch (err) {
if (err instanceof AvenxError) {
console.error(`Avenx error [${err.code}]:`, err.message);
if (err.code === AvenxErrorCodes.MOUNT_TARGET_NOT_FOUND) {
// Handle this specific failure mode
}
} else {
throw err; // Not an Avenx-specific error, rethrow
}
}

Tip: Branch on err.code, not err.messagecode is a stable identifier, while the formatted message text may change between versions.

Non-throwing formatting with formatMessage

Section titled “Non-throwing formatting with formatMessage”

To get the same formatted error string without throwing (for example, to log a warning), use the exported formatMessage helper. It applies the same code-to-template lookup and placeholder substitution as the AvenxError constructor:

import { formatMessage, AvenxErrorCodes } from 'avenx-js';
console.warn(formatMessage(AvenxErrorCodes.SANDBOX_VIOLATION, 'disallowed eval() call'));
// -> "[AVX_R15] Sandbox security violation: disallowed eval() call"
Code Default Message Cause & Resolution
[AVX_C01] Could not create dist directory at “{dir}”. Cause: Write permission failure.
Resolution: Adjust your operating system directory write permissions.
[AVX_C02] “src” directory not found. Cause: Running the build command outside of an Avenx project root.
Resolution: Run npx avenx init to set up the workspace.
[AVX_C03] Duplicate component name(s) detected. These files compile to the same class name: {details} Cause: Two or more component files (e.g. card.component.js in different directories) resolve to the same generated class name, since Avenx-JS derives a component’s class name from its file name. This causes a naming collision when the components are bundled together.
Resolution: Rename one of the conflicting files, or move it to a location that produces a distinct class name — for example, renaming card.component.js to profile-card.component.js. The build halts and lists every conflicting file path so you can identify exactly which components need to be renamed.

Unlike the error codes above, which halt compilation, Avenx-JS also emits warnings during the build step. Warnings do not stop the build, but they flag potential mistakes in your templates that are worth fixing.

The [AVX_W24] warning occurs when a CSS preprocessor is configured but the required preprocessor package is not installed.

[Avenx Validation Warning] Undeclared variable or method "x" referenced in template.

Cause: During compilation, the validateTemplate function (in ComponentParser.js) scans every template for identifiers used in interpolations ({{ }}), bindings (data-ax-bind), loops (<@for>), and event handlers, then cross-checks each one against everything declared in the component’s state, computed, actions, and bridges. If a variable or method is referenced in the template but isn’t declared in any of these sources, Avenx-JS emits this warning at compile time.

This typically happens for a few common reasons:

  • A typo in the variable or method name (e.g. {{ state.usernmae }} instead of {{ state.username }}).
  • Forgetting to declare a new property in state or computed before referencing it in the template.
  • Referencing a method in an event handler (e.g. onclick="handleSubmit") that was never added to actions.
  • Referencing a bridge that wasn’t registered.

Resolution: To resolve this warning:

  1. Double-check the spelling of the identifier in your template against its declaration in the component script.
  2. Make sure the variable or method is actually declared under state, computed, actions, or bridges — not just used implicitly.
  3. If the identifier is intentionally dynamic (e.g. supplied only at runtime through a bridge that isn’t statically known to the parser), you can safely ignore the warning, though most cases indicate a genuine bug.

This validation exists purely to help catch mistakes early — it will not prevent your app from compiling or running, but an undeclared reference will typically resolve to undefined at runtime, so it’s best to address the warning rather than ignore it.

Warning Message

WARNING: {0} exceeds {1} KB ({2} KB)

Cause: This warning is emitted during the bundling phase when a compiled JavaScript chunk or CSS asset exceeds the configured bundle size budget. Avenx-JS compares the final output size of generated assets against the thresholds defined in avenx.config.json. Exceeding these limits does not stop the build, but it indicates that the generated bundle may negatively affect application performance, particularly initial page load times.

This typically happens for a few common reasons:

  • Large third-party dependencies are included in the application bundle.
  • Unused code or assets are bundled unnecessarily.
  • Large images, fonts, or stylesheets are imported directly into the application.
  • Bundle size limits are configured too aggressively for the project’s requirements.

Resolution: To resolve this warning:

  1. Review the generated bundle and identify unusually large JavaScript or CSS assets.
  2. Split large features into smaller modules and load them only when needed.
  3. Remove unused dependencies and assets from the project.
  4. Adjust the configured bundle size budgets if the application’s expected size legitimately exceeds the default limits.

Configure Bundle Budgets

{
"build": {
"bundleBudget": {
"javascript": 500,
"css": 100
}
}
}

The values represent the maximum allowed bundle size (in KB) before Avenx-JS emits a warning.

Optimization Tips

  • Use lazy-loading for large pages or feature modules.
  • Remove unused dependencies and imports.
  • Optimize images and other static assets before bundling.
  • Split large components into smaller, reusable modules.
  • Avoid including development-only libraries in production builds.

Incorrect

import ChartLibrary from "very-large-chart-library";
import "./large-theme.css";

Bundling large dependencies and styles without considering their impact can easily cause bundle size budgets to be exceeded.

Correct

async function loadCharts() {
const { default: ChartLibrary } = await import("very-large-chart-library");
}

Loading large features only when they are required helps reduce the application’s initial bundle size.

Defensive Example

{
"build": {
"bundleBudget": {
"javascript": 750,
"css": 150
}
}
}

Adjust bundle budgets only when larger assets are expected. Increasing the limits should complement optimization efforts, not replace them.

Warning Message

Component "{0}" has an empty template.

Cause: This warning is emitted during compilation when a .component.js or .page.js file contains no HTML template markup or contains only whitespace. Every component in Avenx-JS is expected to define a visual structure. When the component parser extracts the component’s HTML template and finds it empty, the compiler emits AVX_W02.

This typically happens for a few common reasons:

  • A newly scaffolded .component.js file has not had HTML markup added to it yet.
  • The HTML template portion of a component file was accidentally deleted during refactoring.
  • A placeholder component file contains only <state> or <action> tags without any HTML element markup.

Resolution: To resolve this warning:

  1. Add valid HTML markup to the component file.
  2. If the component is a placeholder or no longer used, remove the component file or add a minimal element (e.g. <div></div>).

Incorrect

<!-- Empty component file containing only state and action tags -->
<state count="0" />
<action name="increment">
count++;
</action>
<!-- Missing HTML element markup! Emits AVX_W02 -->

Correct

<state count="0" />
<action name="increment">
count++;
</action>
<div>
<p>Count: {{ count }}</p>
<button @click="increment()">Increment</button>
</div>

Warning Message

Undeclared variable or method "{0}" referenced in template of {1}.

Cause: This warning is emitted during template validation when the compiler encounters a variable, method, or binding that cannot be resolved from the component’s declared members. During compilation, validateTemplate checks template interpolations, bindings, directives, and event handlers against the component’s state, computed, actions, and bridges. If a referenced identifier cannot be resolved statically, Avenx-JS emits this warning.

This typically happens for a few common reasons:

  • A typo in a variable or method name.
  • Referencing a property that was never declared in state.
  • Calling an action that was never added to actions.
  • Using a computed property that does not exist.
  • Referencing a bridge that has not been registered.

Resolution: To resolve this warning:

  1. Verify the spelling of the referenced identifier.
  2. Ensure the property exists in state, computed, actions, or bridges.
  3. Check that renamed variables have been updated throughout the template.
  4. If the reference is intentionally resolved only at runtime (for example, through dynamic properties that cannot be statically analysed), the warning can usually be ignored after confirming the behaviour is expected.

Incorrect

<state username="John" />
<p>{{ usernmae }}</p>
<button @click="saveProfile()">Save</button>
<action name="submit">
console.log("Saving...");
</action>

The template references usernmae instead of username, and calls saveProfile() even though only submit is declared.

Correct

<state username="John" />
<p>{{ username }}</p>
<button @click="submit()">Save</button>
<action name="submit">
console.log("Saving...");
</action>

The template references only declared state and actions, allowing the compiler to resolve every identifier successfully.

Defensive Example

<p>{{ DynamicBridge.currentUser?.name }}</p>

If a value is supplied dynamically at runtime and cannot always be determined during static analysis, the compiler may emit this warning even though the application behaves correctly. Verify the behaviour before deciding to ignore the warning.

Warning Message

Unmatched <@for> tags in template.

Cause: This warning is emitted during template compilation when the parser detects that a <@for> loop block is not properly matched with its corresponding closing tag. During static validation, Avenx-JS verifies that every loop block has a valid opening tag, closing tag, and correctly nested structure. If the parser encounters an incomplete or improperly nested loop, it emits this warning.

This typically happens for a few common reasons:

  • A <@for> block is missing its closing </@for> tag.
  • Loop blocks are nested incorrectly.
  • A closing tag appears without a matching opening tag.
  • Template edits accidentally break the structure of a loop block.

Resolution: To resolve this warning:

  1. Ensure every <@for> opening tag has a matching </@for> closing tag.
  2. Verify that nested loop blocks are opened and closed in the correct order.
  3. Check the template for misplaced or missing tags after editing.
  4. Use consistent indentation to make loop boundaries easier to identify.

Incorrect

<@for item="user" in="users">
<div>{{ user.name }}</div>

Since the <@for> block is never closed, the compiler cannot determine the end of the loop and emits AVX_W04.

Correct

<@for item="user" in="users">
<div>{{ user.name }}</div>
</@for>

The loop block is properly opened and closed, allowing the compiler to parse the template successfully.

Defensive Example

<@for item="group" in="groups">
<h2>{{ group.name }}</h2>
<@for item="user" in="group.users">
<p>{{ user.name }}</p>
</@for>
</@for>

When nesting loop blocks, always close the innermost loop before closing the outer loop. Proper nesting helps the compiler validate the template structure correctly.

AVX_W05 — COMPILER_TRANSITION_PARSE_FAILED

Section titled “AVX_W05 — COMPILER_TRANSITION_PARSE_FAILED”

Warning Message Failed to parse transition tags: {0}

Cause: This warning is emitted at compile time when Avenx-JS extracts and parses transition wrapper attributes (used to animate elements entering/leaving the DOM) but the parser fails to read the class configuration or duration parameters correctly. This typically happens when the transition attribute’s value doesn’t match the format the compiler expects — for example, an invalid duration value, malformed class name syntax, or a missing required parameter.

Expected Format

A transition block is typically declared with an attribute such as data-ax-transition, taking a configuration string with named class and duration parameters:

<div data-ax-transition="name: fade; duration: 300">
Content
</div>
  • name — a string identifying the transition, used to derive the CSS class names applied during enter/leave (e.g. fade-enter, fade-leave).
  • duration — a numeric value in milliseconds specifying how long the transition classes remain applied before being removed.

This typically fails for a few common reasons:

  • The duration value is not a valid number (e.g. duration: 300ms instead of duration: 300).
  • The configuration string is missing a required ; separator between parameters.
  • The name value contains characters that can’t be safely used to construct CSS class names (spaces, quotes, or special characters).
  • A parameter key is misspelled (e.g. duraton instead of duration).

Resolution: To resolve this warning:

  1. Ensure duration is specified as a plain number representing milliseconds, without units.
  2. Separate multiple parameters with a semicolon (;), matching the key: value; key: value format.
  3. Keep name limited to characters valid in CSS class names (letters, numbers, hyphens, underscores).
  4. Double-check parameter key spelling against the supported keys (name, duration).

Incorrect

<div data-ax-transition="name: fade, duration: 300ms">
Content
</div>

This fails because a comma is used instead of a semicolon between parameters, and duration includes the ms unit instead of a plain number.

Correct

<div data-ax-transition="name: fade; duration: 300">
Content
</div>

This produces fade-enter/fade-leave classes applied for 300 milliseconds during the respective transition phase.

Specifying Transition Classes and Durations

You can also override the generated class names directly instead of relying on the name-derived defaults:

<div data-ax-transition="enterClass: slide-in; leaveClass: slide-out; duration: 250">
Content
</div>
  • enterClass — the CSS class applied while the element is entering.
  • leaveClass — the CSS class applied while the element is leaving.
  • duration — shared duration in milliseconds for both phases, unless overridden separately with enterDuration/leaveDuration.

Ensuring these parameters follow the expected key: value pairs, separated by semicolons, with numeric-only duration values, allows the compiler to parse the transition block successfully.

Warning Message

Invalid prop type for "{0}" in component {1}. Expected {2}, got {3}.

Cause: This warning is emitted at runtime when a parent component passes a prop to a child component, but the type of the passed value does not match the expected type defined in the child component’s props schema (e.g., passing a string when Number is required, or passing a number when Boolean is expected).

This typically happens for a few common reasons:

  • Passing a static string literal attribute (e.g. count="5") instead of a dynamic bound property expression (e.g. :count="5").
  • Omitting type conversions when passing values parsed from user input, forms, or URL query parameters.
  • An overly restrictive or mismatched type definition in the child component’s props schema declaration.

Resolution: To resolve this warning:

  1. Use dynamic property binding syntax (:propName="value") to pass non-string primitive types (numbers, booleans, objects, arrays).
  2. Convert values to their expected data types (e.g. Number(state.inputCount)) before passing them as props.
  3. Update the child component’s props schema if the prop’s accepted types should be broadened (e.g., using [String, Number]).

Incorrect

<!-- Parent Component: Passing a string "10" for a prop expecting Number -->
<UserCard count="10" :isActive="true" />

Passing count="10" as a static attribute sends the string '10', causing Avenx-JS to emit AVX_W05 (Expected Number, got String).

Correct

<!-- Parent Component: Using dynamic binding :count="10" to pass numeric 10 -->
<UserCard :count="10" :isActive="true" />
<!-- Child Component (UserCard.component.js) prop declaration -->
<script>
export default {
props: {
count: Number,
isActive: Boolean,
},
};
</script>

AVX_W06 — COMPILER_STATIC_SUBTREE_OPTIMIZATION_FAILED

Section titled “AVX_W06 — COMPILER_STATIC_SUBTREE_OPTIMIZATION_FAILED”

Warning Message Failed to optimize static subtrees: {0}

Cause: As part of its build-time optimizations, the Avenx-JS compiler analyzes each component’s element tree to identify static subtrees — sections of markup that contain no dynamic bindings, interpolations, or directives, and therefore never change after the initial render. Marking these subtrees as static lets the runtime skip re-evaluating and re-diffing them on every update, improving render performance. This warning is emitted when the compiler attempts this analysis but fails, typically because it encounters a malformed tree node or a parser error while walking the template.

This typically happens for a few common reasons:

  • Unclosed or mismatched HTML tags within a section the compiler is trying to statically analyze.
  • Templates that mix static and dynamic content in ways that produce an inconsistent or invalid node structure (e.g. a directive attribute left incomplete or malformed).
  • Deeply nested or unusually structured markup that the tree walker cannot resolve cleanly during the optimization pass.
  • Custom or non-standard elements/attributes that the compiler’s static analyzer doesn’t recognize and cannot safely classify as static or dynamic.

Impact: This is a build-time optimization warning, not a runtime error — it does not stop compilation or break your app’s functionality. However, when a subtree fails static optimization, the runtime is forced to treat it as dynamic and re-evaluate it on every update, which can measurably impact rendering performance in larger or frequently-updating components.

Resolution: To resolve this warning:

  1. Verify that all HTML tags in the affected template are properly closed and correctly nested.
  2. Check that directive attributes (data-ax-*) and interpolations ({{ }}) are complete and well-formed — an incomplete directive can confuse the tree walker.
  3. Simplify unusually deep or complex nesting where possible, particularly in sections you intend to be purely static.
  4. If you’re using custom elements, ensure they follow standard HTML structure so the compiler can correctly classify their contents.

Incorrect

<div class="card">
<p>Static header text</p>
<span>Unclosed span
<p>More static text</p>
</div>

The unclosed <span> produces a malformed node structure, so the compiler cannot reliably determine which parts of this subtree are static.

Correct

<div class="card">
<p>Static header text</p>
<span>Properly closed span</span>
<p>More static text</p>
</div>

With well-formed markup, the compiler can confidently identify this entire subtree as static (since it contains no bindings or directives) and optimize it accordingly.

Subtree Evaluation Requirements

For a subtree to qualify as static and be successfully optimized, it must:

  • Contain no interpolations ({{ }}), directive bindings (data-ax-*), or event handlers.
  • Be well-formed HTML with properly closed and nested tags.
  • Not contain <@for> or other structural directives that produce dynamic output.

Subtrees that meet these requirements are hoisted out of the render function and reused across updates without re-evaluation, improving performance for components with large amounts of unchanging markup.

Warning Message

Page "{0}" is already registered and will be overwritten.

Cause: This warning is emitted when a page is registered more than once using the same registration name. During application initialization, Avenx-JS stores registered pages in its page registry. If another page is later registered with an existing name, the previous entry is overwritten and this warning is emitted.

This typically happens for a few common reasons:

  • The same page is registered multiple times.
  • Two different page components use the same registration name.
  • Duplicate imports or repeated initialization logic register the same page more than once.
  • Copying and modifying route configuration without updating the registration name.

Resolution: To resolve this warning:

  1. Ensure each page is registered only once during application startup.
  2. Use unique registration names for every page.
  3. Check for duplicate imports or repeated initialization code.
  4. Keep page registration centralized to avoid accidental overwrites.

Incorrect

import HomePage from "./pages/home.page.js";
import DashboardPage from "./pages/dashboard.page.js";
const app = new AvenxApp({ target: "#app" });
app.registerPage("Home", HomePage);
app.registerPage("Home", DashboardPage);

Both registrations use the name "Home", so the second registration overwrites the first and Avenx-JS emits AVX_W07.

Correct

import HomePage from "./pages/home.page.js";
import DashboardPage from "./pages/dashboard.page.js";
const app = new AvenxApp({ target: "#app" });
app.registerPage("Home", HomePage);
app.registerPage("Dashboard", DashboardPage);

Using unique registration names ensures each page can be resolved correctly by the router.

Defensive Example

const app = new AvenxApp({ target: "#app" });
app.registerPage("Home", HomePage);
app.registerPage("Profile", ProfilePage);
app.registerPage("Settings", SettingsPage);

Register all pages once during application initialization and assign each page a unique registration name to avoid accidental collisions.

AVX_W08 — ROUTE_PATH_MISSING_LEADING_SLASH

Section titled “AVX_W08 — ROUTE_PATH_MISSING_LEADING_SLASH”

Warning Message

Route path "{0}" lacks a leading slash. This may prevent hash paths from resolving properly.

Cause: This warning is emitted during router initialization when a route is configured with a path that does not begin with a leading /. Avenx-JS expects all route paths to use an absolute, slash-prefixed format so they can be matched correctly during hash-based navigation. If a path is defined without the leading slash, the router may fail to resolve the route as expected.

This typically happens for a few common reasons:

  • The leading / was accidentally omitted when defining a route.
  • A route path was copied or renamed without preserving the correct format.
  • Route configurations were generated dynamically without normalizing the path.

Resolution: To resolve this warning:

  1. Ensure every route path begins with a leading /.
  2. Review route definitions for typos or inconsistent path formatting.
  3. Normalize dynamically generated paths before registering them with the router.
  4. Keep route definitions consistent throughout the application.

Incorrect

const routes = [
{
path: "dashboard",
component: DashboardPage,
},
];

Since the route path does not begin with /, Avenx-JS emits AVX_W08 and the route may not match incoming hash navigation correctly.

Correct

const routes = [
{
path: "/dashboard",
component: DashboardPage,
},
];

Using a leading slash ensures the router can correctly match and resolve the route.

Defensive Example

const normalizePath = (path) =>
path.startsWith("/") ? path : `/${path}`;
const routes = [
{
path: normalizePath("dashboard"),
component: DashboardPage,
},
];

Normalizing route paths before registration helps prevent configuration mistakes and ensures all routes follow the expected format.

Warning Message

Failed to decode route parameter "{0}": {1}

Cause: This warning is emitted at runtime when the router matches a URL hash containing dynamic path parameters or query arguments, but decodeURIComponent fails to decode one of the percent-encoded values due to a malformed or invalid percent sequence (such as #/profile/%invalid or #/search?query=%E0%A4%A).

Fallback Behavior: When URI decoding fails, Avenx-JS catches the URIError, logs warning AVX_W09, and falls back to passing the raw, undecoded parameter string directly to the component props / route params object. This prevents routing navigation from crashing with an unhandled exception.

This typically happens for a few common reasons:

  • A link or user input contains an unescaped % character followed by invalid hexadecimal digits.
  • A URL parameter string was manually constructed without using encodeURIComponent().
  • An external redirect or truncated URL link passed malformed percent-encoded sequences into the hash path.

Resolution: To resolve this warning:

  1. Ensure all dynamically generated URL path parameters and query strings are encoded using encodeURIComponent() before appending them to navigation hashes.
  2. Validate user-entered search queries or input before interpolating them into URL hashes.
  3. Handle potential raw undecoded string fallbacks defensively inside route components if malformed external links are expected.

Incorrect

// Manually concatenating parameter strings without encoding
const category = "books & magazines % special";
// Creates malformed hash with unescaped '%' -> '#/category/books%20&%20magazines%20%20special'
window.location.hash = `#/category/${category}`;

The malformed percent sequence triggers a URIError inside decodeURIComponent, causing Avenx-JS to emit AVX_W09 and pass the raw undecoded string into params.category.

Correct

// Correctly encoding dynamic route parameters
const category = "books & magazines % special";
const safeCategory = encodeURIComponent(category);
// Produces valid percent-encoded hash: '#/category/books%20%26%20magazines%20%25%20special'
window.location.hash = `#/category/${safeCategory}`;

Warning Message

No route defined for hash: {0}

Cause: This warning is emitted when the router detects a hash-based navigation request that does not match any registered route in the application’s routing table. Since no matching page can be resolved, Avenx-JS cannot complete the navigation and emits this warning.

This typically happens for a few common reasons:

  • Navigating to a URL hash that has no corresponding route.
  • A typo in the route path or hash.
  • The route was removed or renamed but existing links still reference it.
  • A fallback or wildcard route has not been configured.

Resolution: To resolve this warning:

  1. Verify that the requested hash matches a registered route.
  2. Update any broken links or navigation code that references outdated route paths.
  3. Define a fallback or wildcard route to handle unknown URLs gracefully.
  4. Redirect unmatched routes to a dedicated 404 page instead of leaving the application in an undefined state.

Incorrect

const router = new AvenxRouter();
router.add('/home', HomePage);
// User navigates to:
// #/profile

Since /profile is not registered, the router emits AVX_W10 because no matching route exists.

Correct

const router = new AvenxRouter();
router.add('/home', HomePage);
router.add('/profile', ProfilePage);

Registering every navigable route ensures hash navigation can resolve successfully.

Defensive Example

const router = new AvenxRouter();
router.add('/home', HomePage);
router.add('/profile', ProfilePage);
router.add('*', NotFoundPage);

Using a wildcard (fallback) route allows unknown hashes to be redirected to a dedicated 404 page instead of producing an unresolved navigation.

Warning Message

Duplicate route name "{0}". Route names should be unique.

Cause: This warning is emitted during router setup when multiple route definitions in the router configuration share the exact same name property. Route names serve as unique string keys for named route navigation (e.g., router.push({ name: 'user-profile' })) and path resolution. When two or more routes use identical names, the router cannot determine which route to resolve and emits AVX_W11.

This typically happens for a few common reasons:

  • Copying and pasting a route configuration block without updating the name property.
  • Assigning generic names (such as 'details' or 'index') across multiple nested or feature route modules.
  • Registering duplicate routes dynamically during application initialization.

Resolution: To resolve this warning:

  1. Ensure every route in your router configuration has a unique name string identifier.
  2. Follow a consistent naming convention (e.g. prefixing route names with feature areas like 'user-profile' and 'company-profile').
  3. Audit route definitions to remove duplicate entries or conflicting names.

Incorrect

const routes = [
{
path: '/users/:id',
name: 'profile', // Duplicate route name!
component: UserProfilePage,
},
{
path: '/company/profile',
name: 'profile', // Conflict triggers AVX_W11
component: CompanyProfilePage,
},
];

Correct

const routes = [
{
path: '/users/:id',
name: 'user-profile', // Unique route name
component: UserProfilePage,
},
{
path: '/company/profile',
name: 'company-profile', // Unique route name
component: CompanyProfilePage,
},
];

Route Title Evaluation Warning (title() Error)

If AVX_W11 is triggered during dynamic page title evaluation when a route’s title() callback throws an exception:

// Ensure title() safely accesses route parameters or fallback titles
export default {
path: '/users/:id',
name: 'user-profile',
title: (route) => route.params?.id ? `User ${route.params.id}` : 'User Profile',
};

Warning Message Failed to evaluate prop expression: {0}. Error: {1}

Cause: This warning is emitted during the mounting lifecycle of a routed page when a property mapped to that route — via a route parameter, query mapping, or resolver — fails to resolve or throws an exception during evaluation. Since page props are typically evaluated before the page component fully mounts, an error here can prevent the page from receiving the data it expects.

This typically happens for a few common reasons:

  • A resolver function tied to the route throws an exception (e.g. it depends on data that hasn’t loaded, or accesses a property on null/undefined).
  • A prop expression references a route parameter or query value that doesn’t exist for the current navigation.
  • An asynchronous resolver rejects instead of resolving, and the rejection isn’t handled.
  • A typo or syntax error in the prop mapping expression itself.

Resolution: To resolve this warning:

  1. Ensure resolver functions handle missing or undefined route parameters gracefully, with a sensible fallback value instead of throwing.
  2. Wrap resolver logic in a try...catch (or handle promise rejections) so failures produce a controlled fallback rather than an unhandled error.
  3. Double-check that prop expressions reference route parameters and query keys that actually exist for every route the page can be reached from.
  4. If a prop depends on asynchronous data (e.g. an API call), provide a default/loading value so the page can mount safely while data resolves.

Incorrect

const pageProps = {
userId: (route) => route.params.user.id
};
<!-- Route: /profile (no "user" param defined) -->

Since route.params.user is undefined for this route, accessing .id throws, and the prop expression fails to evaluate.

Correct

const pageProps = {
userId: (route) => route.params.userId || null
};
<!-- Route: /profile/:userId -->

Defensive Example

const pageProps = {
userId: (route) => {
try {
return route.params.userId ?? null;
} catch (err) {
console.warn('Failed to resolve userId prop:', err);
return null;
}
}
};

Wrapping the resolver and falling back to a safe default ensures the page can still mount even if the expected route data is missing, rather than failing the prop evaluation entirely.

Warning Message

Component "{0}" not found in registry.

Cause: This warning is emitted when the router attempts to mount a page whose registered component cannot be found in the application’s page registry. Before a page can be mounted, it must first be imported and registered with the AvenxApp instance. If the router resolves a page name that has never been registered, Avenx-JS cannot create the page and emits this warning.

This typically happens for a few common reasons:

  • The page component was never imported.
  • The page was imported but not registered using app.registerPage().
  • The registration name does not match the name used when mounting or routing.
  • The page registration occurs after routing has already started.

Resolution: To resolve this warning:

  1. Ensure the page component is imported into your application’s entry file.
  2. Register the page with app.registerPage() before any routing or page mounting occurs.
  3. Verify that the registration name exactly matches the name referenced by your routes or app.mountPage().
  4. Keep all page registrations together during application initialization so the router has access to every page before navigation begins.

Incorrect

import { AvenxApp } from 'avenx-core/runtime';
import Home from './pages/home.page.js';
const app = new AvenxApp({ target: '#app' });
app.mountPage('Home');

Since the page was never registered, Avenx-JS cannot locate the component in the page registry.

Correct

import { AvenxApp } from 'avenx-core/runtime';
import Home from './pages/home.page.js';
const app = new AvenxApp({ target: '#app' });
app.registerPage('Home', Home);
app.mountPage('Home');

Registering the page before mounting ensures the router can resolve the requested component successfully.

Defensive Example

import { AvenxApp } from 'avenx-core/runtime';
import Home from './pages/home.page.js';
import Profile from './pages/profile.page.js';
const app = new AvenxApp({ target: '#app' });
app.registerPage('Home', Home);
app.registerPage('Profile', Profile);
app.mountPage('Home');

Registering all pages during application startup helps ensure every routed page is available before navigation begins.

AVX_W14 — COMPONENT_RESTORE_SLOT_CONTENT_FAILED

Section titled “AVX_W14 — COMPONENT_RESTORE_SLOT_CONTENT_FAILED”

Warning Message Failed to restore default slot content. Error: {0}

Cause: This warning relates to how Avenx-JS handles component slots — placeholder regions inside a component’s template where a parent can inject custom (“transcluded”) content, falling back to the component’s own default markup when nothing is provided. When transcluded content is unmounted (for example, when a parent stops passing slot content, or the component itself unmounts and remounts), Avenx-JS attempts to restore the slot’s original default template elements so the component returns to a consistent state. This warning is emitted when that restore step fails.

This typically happens for a few common reasons:

  • Code outside the component (custom DOM manipulation, a third-party library, or a browser extension) directly mutated the DOM nodes inside the slot, so the renderer’s internal reference to the original default content no longer matches the live DOM.
  • The default slot content itself contained elements that were later removed or replaced by other framework logic before the restore attempt ran.
  • Rapid mount/unmount cycles on the same component instance interrupted the restore process before it completed.

Impact: When this restore fails, the slot may be left empty or in an inconsistent state rather than falling back to the component’s intended default content. This is a rendering consistency issue, not a security issue, but it can result in visibly broken or missing UI where default slot content was expected.

Resolution: To resolve this warning:

  1. Avoid directly mutating the DOM inside a component’s slot region from outside the framework (e.g. via document.querySelector plus manual appendChild/removeChild calls). Let Avenx-JS own all DOM updates within its managed tree.
  2. If you’re integrating a third-party library that manipulates the DOM (such as a jQuery plugin or a non-Avenx widget), mount it outside the component’s slot boundary, or use a dedicated wrapper/bridge pattern instead of injecting it directly into slot content.
  3. Avoid rapidly toggling a component’s mounted state or its slot content in the same render cycle; batch these changes where possible.
  4. If the warning persists without any external DOM manipulation, it may indicate a genuine bug — check for other components or event handlers that could be mutating shared DOM nodes.

Incorrect

// Directly manipulating DOM nodes inside a component's slot from outside Avenx-JS
const slotContainer = document.querySelector('.my-component .slot-content');
slotContainer.innerHTML = '<p>Injected externally</p>';

Manipulating the slot’s DOM outside of Avenx-JS’s rendering tree causes the renderer’s internal reference to the default content to become stale, so it cannot reliably restore it later.

Correct

<MyComponent>
<p>Custom transcluded content</p>
</MyComponent>

Pass content through the component’s own slot mechanism so Avenx-JS can track and restore it correctly.

Defensive Example

// If integrating a non-Avenx widget, mount it in its own container
// outside the component's slot boundary rather than inside it.
<MyComponent></MyComponent>
<div id="third-party-widget-container"></div>

Keeping externally-managed DOM separate from Avenx-managed slot regions prevents the renderer from losing track of default slot content.

AVX_W15 — COMPONENT_INJECT_KEY_NOT_FOUND

Section titled “AVX_W15 — COMPONENT_INJECT_KEY_NOT_FOUND”

Warning Message

Injected key "{0}" not found in any ancestor component.

Cause: This warning is emitted at runtime when a component’s inject option requests a key that no ancestor component provides via the provide option. Avenx-JS walks up the DOM tree from the component to find a matching provider; if none is found, the injected property resolves to undefined and this warning is issued.

The Provide/Inject API enables parent components to share data or methods with all descendants in the tree without passing them through every intermediate component via props. A provider component declares values using provide, and any descendant retrieves them using inject.

Resolution: To resolve this warning:

  1. Ensure an ancestor component declares the requested key in its provide option.
  2. Verify the component hierarchy — the provider must be an ancestor in the DOM tree (sibling and child components are not searched).
  3. If the injected value is optional, guard against undefined at the point of use with a fallback value.

Incorrect

// ChildComponent
export default {
inject: ['theme'],
template: `<p>Theme: {{ theme }}</p>`,
};

No ancestor provides a theme key, so accessing theme triggers AVX_W15 and returns undefined.

Correct

// ParentComponent
export default {
provide: {
theme: 'dark',
},
// ...
};
// ChildComponent
export default {
inject: ['theme'],
template: `<p>Theme: {{ theme }}</p>`,
};

The provide option accepts an object mapping keys to values, or an array of keys to expose from the component’s state, props, computed, or actions. The inject option accepts an array of keys (local key matches provide key) or an object mapping local property names to provide keys:

export default {
inject: { currentTheme: 'theme' },
template: `<p>Theme: {{ currentTheme }}</p>`,
};

Defensive Example

// ChildComponent — handle optional injection with a default value
export default {
inject: { currentTheme: 'theme' },
computed: {
safeTheme() {
return this.currentTheme || 'light';
},
},
};

Using a computed property as a fallback ensures your component behaves gracefully even when no matching provider exists in the ancestor tree.

Warning Message Sanitized tag “<{0}>” when stripping content.

Cause: This warning is emitted when Avenx-JS’s HTML sanitizer detects a forbidden or potentially dangerous tag inside dynamic content being rendered (for example, through data-ax-html) and strips it before injecting the content into the DOM. This is a security safeguard against cross-site scripting (XSS) attacks, since dynamic HTML from user input, API responses, or other untrusted sources could otherwise execute arbitrary scripts or embed malicious content.

By default, Avenx-JS forbids the following tags when sanitizing dynamic HTML:

  • <script>
  • <object>
  • <embed>
  • <iframe>
  • <link>
  • <style>
  • <form>

Any of these tags found in dynamic content are stripped out, and this warning is logged so developers are aware the sanitizer intervened.

Why these tags are flagged: Each of these tags can be used to execute or load unauthorized code or content:

  • <script> can run arbitrary JavaScript.
  • <object>, <embed>, and <iframe> can load external content or plugins outside the app’s control.
  • <link> and <style> can be used for CSS-based attacks or to exfiltrate data via crafted stylesheets.
  • <form> can be used to construct unauthorized submissions, including phishing-style attacks.

Resolution: This warning does not indicate a bug to “fix” in the traditional sense — it means the sanitizer is working as intended. However, if you’re seeing it unexpectedly:

  1. Confirm the dynamic content actually needs to include the flagged tag. In most cases it doesn’t, and the warning can be safely ignored.
  2. If you legitimately need to render rich content (e.g. embedding a video), use a dedicated, purpose-built component instead of raw HTML injection — this keeps the source of the embed under your control rather than passing through arbitrary untrusted markup.
  3. Never bypass or disable the sanitizer to “fix” this warning. If you find yourself needing to allow a forbidden tag, treat that as a sign the approach needs to change, not the sanitizer.

Example

const state = {
userBio: '<p>Hello!</p><script>alert("xss")</script>',
};
<div data-ax-html="state.userBio"></div>

When rendered, the sanitizer strips the <script> tag and logs:

[Avenx Validation Warning] Sanitized tag "<script>" when stripping content.

The safe portion of the markup (<p>Hello!</p>) still renders normally.

Safe Alternative

const computed = {
safeBio() {
return sanitizeUserContent(state.userBio); // pre-sanitized on the server, or use a trusted markdown renderer
},
};
<div data-ax-html="computed.safeBio"></div>

Sanitizing or escaping dynamic content at the source — before it ever reaches data-ax-html — avoids relying on the framework’s sanitizer as a last line of defense.

[Avenx Validation Warning] Sanitized attribute "{0}" when stripping content.

Cause: This warning is emitted when Avenx’s HTML sanitizer detects an unsafe HTML attribute or URI while processing templates or raw values. To protect applications from Cross-Site Scripting (XSS) attacks, the sanitizer removes dangerous inline event handler attributes (such as onclick, onload, and onerror) and unsafe URI protocols (such as javascript:) before rendering.

Impact: Unsafe attributes and protocol URIs can allow arbitrary JavaScript execution in the browser, creating Cross-Site Scripting (XSS) vulnerabilities. Sanitizing these values helps prevent malicious code from being executed.

Resolution: To resolve this warning:

  1. Remove inline event handler attributes such as onclick, onload, and onerror.
  2. Avoid using javascript: or other unsafe URI protocols in attributes such as href or src.
  3. Attach event handlers using the framework’s supported event binding mechanism or standard JavaScript event listeners.
  4. Sanitize any user-provided HTML before rendering it.

Incorrect

<img src="image.png" onerror="alert('XSS')" />
<a href="javascript:alert('Hello')">Click me</a>

Correct

button.addEventListener('click', handleClick);
<a href="/dashboard">Dashboard</a>

Note: This warning indicates that Avenx removed one or more unsafe attributes during sanitization. Although the application can continue running, the affected attribute will not be rendered. Review the source HTML and replace unsafe attributes with secure alternatives.

Warning Message

Failed to evaluate list expression: {0}. Error: {1}

Cause: This warning is emitted at runtime when Avenx-JS attempts to evaluate a dynamic list expression used in <@for> or data-ax-for, but the expression throws an exception or does not resolve to a valid iterable. This commonly occurs when the referenced variable is undefined, null, not an array or iterable, or when the expression itself contains an error.

Resolution: To resolve this warning:

  1. Ensure the list variable is declared before it is used in the template.
  2. Verify that the evaluated value is an array or another iterable object.
  3. Check for typographical errors in variable or property names.
  4. Initialize dynamic lists with an empty array when data may not yet be available.
  5. If the list depends on asynchronous data, ensure the data has loaded before rendering.

Incorrect

const state = {};
<@for="user in state.users">
{{ user.name }}
</@for>

Since state.users is undefined, the renderer cannot evaluate the list expression.

Correct

const state = {
users: [],
};
<@for="user in state.users">
{{ user.name }}
</@for>

Defensive Example

const users = Array.isArray(state.users) ? state.users : [];

Using a default empty array ensures that the renderer always receives a valid iterable and prevents evaluation failures.

Warning Message

Failed to evaluate list key expression: {0}. Error: {1}

Cause: This warning is emitted at runtime when Avenx-JS attempts to evaluate the expression provided to data-ax-key, but the expression throws an exception. This commonly happens when the expression references an undefined property, calls a method that throws, or contains an invalid expression.

Impact: The list continues to render, but Avenx-JS falls back to using the item’s index as the key for the affected item. While rendering can continue, using index-based keys may reduce the effectiveness of keyed DOM updates if the list is reordered or modified.

Resolution: To resolve this warning:

  1. Ensure the expression used in data-ax-key references properties that exist for every item.
  2. Check for typographical errors in property or method names.
  3. Avoid calling methods that can throw exceptions while computing the key.
  4. Prefer stable, unique values such as database IDs or UUIDs.

Incorrect

const state = {
users: [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
]
};
<li
data-ax-for="user in state.users"
data-ax-key="user.profile.id"
>
{{ user.name }}
</li>

Since the profile property does not exist on every user object, evaluating the key expression throws and this warning is emitted.

Correct

<li
data-ax-for="user in state.users"
data-ax-key="user.id"
>
{{ user.name }}
</li>

Each item provides a stable, unique key that can be evaluated successfully.

Defensive Example

<li
data-ax-for="user in state.users"
data-ax-key="user?.id ?? index"
>
{{ user.name }}
</li>

Using a fallback expression ensures every item can produce a valid key, even when some objects are missing the preferred identifier.

Note: When a key expression cannot be evaluated, Avenx-JS logs this warning and falls back to using the item’s index as the key so rendering can continue.

Warning Message

[Avenx Validation Warning] Duplicate key "{0}" detected in list expression "{1}". Appending index suffix to prevent node reuse conflict.

Cause: This warning is emitted at runtime by the ListManager reconciliation engine when two or more items rendered from the same list evaluate to the exact same key value. Avenx-JS relies on unique keys to track, reorder, and update DOM nodes efficiently during reactive updates. When duplicate keys exist, the renderer cannot uniquely distinguish between list elements.

Impact: Duplicate keys break Virtual DOM list reconciliation and degrade application performance:

  • Performance Overhead: To prevent execution crashes, Avenx-JS executes a fallback index-suffixing algorithm (key_0, key_1). This bypasses optimal DOM element recycling, causing unnecessary DOM element creation and destruction cycles on list updates.
  • State Mismatches & UI Glitches: Re-using DOM elements with duplicate keys can result in component state leakage, incorrect form input focus, broken CSS animation transitions, or stale content remaining in rendered list items.

Resolution: To resolve this warning:

  1. Ensure every item in your list supplies a property that is guaranteed to be unique across all items (such as a database id or UUID).
  2. Avoid using non-unique attributes like user.role, item.category, or static string literals as key expressions.
  3. If list items lack a native unique identifier, construct a composite key or combine the item property with the loop index (e.g. item.category + '-' + index).
  4. Verify that source data in state does not contain duplicate entries with identical IDs.

Incorrect

Using duplicate keys in <@for> loop tag syntax:

<state users="[
{ id: 101, role: 'admin', name: 'Alice' },
{ id: 102, role: 'admin', name: 'Bob' }
]" />
<!-- ❌ Non-unique key: Both items evaluate to role 'admin' -->
<@for item="user" in="state.users" key="user.role">
<div class="user-card">{{ user.name }} ({{ user.role }})</div>
</@for>

Using duplicate keys in data-ax-for directive syntax:

<!-- ❌ Duplicate ID in source state array -->
<li
data-ax-for="user in state.users"
data-ax-key="user.id"
>
{{ user.name }}
</li>

Correct

Using unique id properties in <@for> loop tag syntax:

<state users="[
{ id: 101, role: 'admin', name: 'Alice' },
{ id: 102, role: 'admin', name: 'Bob' }
]" />
<!-- ✅ Unique key: Every user has a distinct id -->
<@for item="user" in="state.users" key="user.id">
<div class="user-card">{{ user.name }} ({{ user.role }})</div>
</@for>

Using unique id properties in data-ax-for directive syntax:

<!-- ✅ Unique key expression for each item -->
<li
data-ax-for="user in state.users"
data-ax-key="user.id"
>
{{ user.name }}
</li>

Defensive Example

When items do not possess guaranteed unique IDs, construct a composite key or use a safe fallback:

<!-- ✅ Composite key fallback using loop index -->
<@for item="user" in="state.users" key="user.id ? user.id : 'user-' + index">
<div class="user-card">{{ user.name }}</div>
</@for>

Note: When duplicate keys are detected, Avenx-JS automatically appends an index suffix (e.g. key_0, key_1) so rendering can complete without throwing an error. However, this fallback degrades DOM reconciliation performance and should be resolved by assigning unique keys.

AVX_W21 — DIRECTIVE_HTML_EVALUATION_FAILED

Section titled “AVX_W21 — DIRECTIVE_HTML_EVALUATION_FAILED”

Warning Message

Failed to evaluate data-ax-html: {0}. Error: {1}

Cause: This warning is emitted at runtime when Avenx-JS attempts to evaluate the expression bound to a data-ax-html="..." directive, but the expression throws an exception during evaluation. Since data-ax-html injects raw HTML directly into the element’s innerHTML, any error in the underlying expression — such as referencing an uninitialized variable, calling an undefined method, or a malformed expression — prevents the directive from resolving to a valid HTML string.

This typically happens for a few common reasons:

  • The bound expression references a state variable or property that is undefined or null at the time of evaluation.
  • A method called within the expression throws internally (e.g. a formatting or sanitization helper failing on unexpected input).
  • Asynchronous data the expression depends on has not finished loading.
  • A typo or syntax error exists in the expression itself.

[!WARNING] Security Guidelines for Raw HTML Bindings (data-ax-html): data-ax-html renders unescaped raw HTML using innerHTML. Inserting untrusted user input directly via data-ax-html creates severe Cross-Site Scripting (XSS) vulnerabilities.

  1. Use Interpolation by Default: Use standard template interpolations ({{ content }}) whenever possible. Avenx-JS automatically escapes HTML in interpolations to protect against XSS.
  2. Sanitize Untrusted HTML: If you must render dynamic HTML from an API or user input, sanitize the content using a trusted HTML sanitizer (such as DOMPurify) before binding it to data-ax-html.
  3. Avoid Dynamic Code Execution: Never construct executable scripts or event handlers within HTML strings bound to data-ax-html.

Resolution: To resolve this warning:

  1. Ensure all state variables referenced in data-ax-html are declared in <state />.
  2. Guard against undefined/null values with defensive checks or fallback strings.
  3. Handle asynchronous data by providing safe initial default values (e.g. description="").
  4. Encapsulate complex HTML generation logic within <computed /> properties to keep template expressions clean and testable.

Incorrect

<!-- State initialized without 'description' property -->
<state />
<div data-ax-html="description.toUpperCase()"></div>

Since description is undefined, calling .toUpperCase() throws a TypeError, triggering AVX_W21.

Correct

<state description="" />
<div data-ax-html="description"></div>

Defensive Example with Computed Property

<state rawContent="null" />
<computed name="safeContent" value="typeof rawContent === 'string' ? rawContent : ''" />
<div data-ax-html="safeContent"></div>

Deriving the HTML content through a guarded <computed> property ensures data-ax-html always receives a valid string and prevents evaluation failures.

AVX_W22 — DIRECTIVE_SHOW_EVALUATION_FAILED

Section titled “AVX_W22 — DIRECTIVE_SHOW_EVALUATION_FAILED”

Warning Message

Failed to evaluate data-ax-show: {0}. Error: {1}

Cause: This warning is emitted at runtime when Avenx-JS attempts to evaluate the condition expression bound to a data-ax-show="..." directive, but the evaluation throws a runtime exception. Since data-ax-show dynamically toggles an element’s visibility based on the truthiness of the evaluated expression, an evaluation error — such as accessing properties on an uninitialized or undefined state property — prevents the renderer from determining whether the element should be shown or hidden.

This typically happens for a few common reasons:

  • The bound expression accesses a property on an undefined or null state object (e.g. state.user.isActive when state.user is uninitialized or pending an async fetch).
  • An uninitialised state variable is referenced directly before component state setup completes.
  • A method referenced in the expression is missing from actions or computed.
  • A syntax error or typo exists within the directive expression string.

Resolution: To resolve this warning:

  1. Initialize State Properties: Ensure state variables referenced in data-ax-show are defined in initial component state (e.g. user: null or user: {}).
  2. Use Defensive Guarding / Optional Chaining: Guard property access on potentially undefined state values (e.g. state.user && state.user.isActive or state.user?.isActive).
  3. Handle Async Data State: Default state properties to safe initial fallback values (e.g., false) so data-ax-show evaluates safely while waiting for API responses.
  4. Use Computed Properties for Complex Expressions: Encapsulate conditional state evaluation in a computed property with internal error handling or fallback logic.

Incorrect

<!-- State initialised without 'user' property -->
<state />
<div data-ax-show="user.isActive">Welcome back!</div>

Since user is undefined, accessing .isActive throws a TypeError, triggering AVX_W22.

Correct

<state user="null" />
<div data-ax-show="user && user.isActive">Welcome back!</div>

Defensive Example

<state user="null" />
<computed name="isUserActive" value="Boolean(user && user.isActive)" />
<div data-ax-show="isUserActive">Welcome back!</div>

Deriving the condition through a guarded <computed> property ensures data-ax-show always receives a safe boolean and prevents evaluation failures.

AVX_W23 — DIRECTIVE_CLASS_EVALUATION_FAILED

Section titled “AVX_W23 — DIRECTIVE_CLASS_EVALUATION_FAILED”

Warning Message Failed to evaluate data-ax-class: {0}. Error: {1}

Cause: This warning is emitted at runtime when Avenx-JS attempts to evaluate the expression bound to a data-ax-class="..." directive, but the expression throws an exception. Since data-ax-class adds and removes classes based on the evaluated value, any error during evaluation prevents the renderer from applying the intended dynamic classes for that update.

This typically happens for a few common reasons:

  • The bound expression accesses a nested property on a value that is null or undefined (e.g. user.role before user has loaded).
  • A class map references an action or computed value that has not been declared.
  • Asynchronous data used to choose classes has not resolved yet.
  • A typo or syntax error prevents the expression from evaluating.

Resolution: To resolve this warning:

  1. Initialize any state used by data-ax-class before the component renders.
  2. Guard nested property access with optional chaining or explicit checks.
  3. Return either a string of class names or an object whose keys are class names and whose values are booleans.
  4. Move complex class decisions into a <computed> property so the template stays small and the logic is easier to test.

Incorrect

<state />
<button data-ax-class="{ admin: user.role === 'admin' }">
Save
</button>

Since user is undefined, accessing .role throws, and the dynamic class expression fails to evaluate.

Correct

<state user="null" />
<button data-ax-class="{ admin: user && user.role === 'admin' }">
Save
</button>

Defensive Example

<state user="null" isSaving="false" />
<computed name="buttonClasses" value="{ admin: user?.role === 'admin', loading: isSaving === true }" />
<button data-ax-class="buttonClasses">Save</button>

Deriving class maps through guarded <computed> properties ensures data-ax-class receives a safe value and prevents evaluation failures when optional state is missing.

Warning Message

Navigation guard for route "{0}" returned undefined. Guards should explicitly return true, false, a redirect string, or a control object. Defaulting to allow.

Cause: This warning is emitted at runtime when a route guard’s canActivate(to, from) method resolves to undefined instead of returning an explicit decision. By design, route guards must explicitly dictate navigation behavior by returning:

  • true: Allow navigation
  • false: Abort navigation
  • string: Redirect to another route (e.g., '#/login')
  • object: Guard control object (e.g., { cancel: true } or { redirect: '#/login' })

When a guard returns undefined, Avenx-JS logs AVX_W27 and defaults to allowing the transition. This usually indicates a logic bug such as a missing return statement or an unhandled code branch in an if/else block within the guard.

This typically happens for a few common reasons:

  • Forgetting an explicit return statement at the end of canActivate().
  • An if condition branch performs a check but fails to return true on the fallback/else branch.
  • An async guard resolves an asynchronous operation without explicitly returning a boolean or redirect string.

Resolution: To resolve this warning:

  1. Ensure every execution path inside canActivate() explicitly returns a boolean, string, or control object.
  2. Add a default fallback return true; (or return false;) at the end of the canActivate() method.
  3. Review if/else conditional logic inside custom route guards to guarantee all branches return an explicit value.

Incorrect

import { AvenxGuard } from 'avenx-core/runtime';
export default class AuthGuard extends AvenxGuard {
canActivate(to, from) {
if (!localStorage.getItem('authToken')) {
return '#/login';
}
// Missing explicit return true on authorized path!
// Implicitly returns undefined, triggering AVX_W27
}
}

Correct

import { AvenxGuard } from 'avenx-core/runtime';
export default class AuthGuard extends AvenxGuard {
canActivate(to, from) {
if (!localStorage.getItem('authToken')) {
return '#/login';
}
// Explicit return for allowed navigation
return true;
}
}

Async Example

import { AvenxGuard } from 'avenx-core/runtime';
export default class AsyncRoleGuard extends AvenxGuard {
async canActivate(to, from) {
try {
const user = await fetchCurrentUser();
if (!user || user.role !== 'admin') {
return '#/unauthorized';
}
return true;
} catch {
return false; // Explicit return on error
}
}
}

Warning Message

WARNING: Preprocessor module "{0}" is not installed. Falling back to raw CSS.

Cause: This warning is emitted during compilation when a style preprocessor package (such as sass, less, or postcss) is configured in avenx.config.json but is not installed in the project’s node_modules. Avenx-JS attempts to load the specified preprocessor to compile stylesheets (.scss, .sass, .less, or PostCSS files), but if the required package is missing, the compiler gracefully falls back to processing the raw CSS content without transformation.

This typically happens for a few common reasons:

  • The preprocessor package was never installed (e.g. npm install sass was not run).
  • The package was removed from node_modules (e.g. after running npm prune).
  • A lock file mismatch caused the preprocessor to not be installed during npm install.
  • The preprocessor is listed in avenx.config.json but the project only needs vanilla CSS.

Resolution: To resolve this warning:

  1. Install the required preprocessor package using your package manager (e.g. npm install sass for Sass/SCSS, npm install less for Less, or npm install postcss postcss-cli for PostCSS).
  2. Verify the preprocessor value in your avenx.config.json matches the installed package.
  3. If you do not need a preprocessor, remove the preprocessor field from the configuration or set it to none.
  4. After installing, re-run the build to confirm the warning no longer appears.

Incorrect

{
"compiler": {
"preprocessor": "sass"
}
}

If the sass package is not installed, Avenx-JS emits AVX_W24 and falls back to raw CSS.

Correct

Terminal window
npm install sass

Installing the preprocessor package resolves the missing module issue.

Defensive Example

If your project does not use a preprocessor, omit the field entirely or set it explicitly:

{
"compiler": {
"preprocessor": "none"
}
}

This avoids the warning and ensures stylesheets are processed as vanilla CSS.

Warning Message

Failed to parse avenx.config.json at "{0}": {1}

Cause: This warning is emitted during project build or compilation when Avenx-JS attempts to load and parse avenx.config.json at the root of your project, but the JSON configuration file is malformed (e.g. invalid JSON syntax, trailing commas, missing quotes) or contains unparseable values. When config parsing fails, Avenx-JS catches the exception, logs warning AVX_W25, and gracefully falls back to default compiler settings.

This typically happens for a few common reasons:

  • Syntax errors in avenx.config.json such as trailing commas, single quotes instead of double quotes, or missing closing braces.
  • Invalid data types or malformed configuration schemas.
  • File encoding issues or partial writes during build tooling execution.

Resolution: To resolve this warning:

  1. Validate the syntax of avenx.config.json using a JSON validator or IDE formatting tool.
  2. Ensure standard double quotes (") are used around all keys and string values.
  3. Remove any trailing commas after the last key-value pair in JSON objects or arrays.
  4. Verify configuration schema keys (e.g. preprocessors, bundleBudget, voidTags) match the expected framework options.

Incorrect

// Malformed JSON: single quotes and trailing comma -> Triggers AVX_W25
{
'srcDir': 'src',
'bundleBudget': 500,
}

Correct

{
"srcDir": "src",
"build": {
"bundleBudget": {
"javascript": 500,
"css": 100
}
},
"voidTags": ["my-custom-tag"]
}

Warning Message

Error compiling {0}: {1}

Cause: This warning is emitted during project build or template compilation when a preprocessor (e.g. Sass/SCSS, Less, PostCSS, or a custom template transformer hook configured in avenx.config.json) throws an exception during execution. When a preprocessor fails due to syntax errors in the source language, invalid preprocessor hooks, or unexpected return values, AvenxCompiler catches the exception, logs warning AVX_W26, and gracefully falls back to using the raw, un-preprocessed template or stylesheet content.

This typically happens for a few common reasons:

  • Syntax errors inside preprocessed stylesheets or templates (e.g. invalid SCSS syntax, unclosed braces, or malformed Pug template indentations).
  • A custom preprocessor function throws an unhandled exception or returns undefined / null instead of a compiled string.
  • Incompatible preprocessor plugin versions or missing secondary plugins (e.g., PostCSS plugins configured with invalid options).

Resolution: To resolve this warning:

  1. Inspect the detailed error message in build logs to pinpoint the exact file path and line number where the preprocessor failed.
  2. Fix syntax errors inside your .scss, .less, or preprocessed template blocks.
  3. Wrap custom preprocessor functions in try...catch blocks or ensure they always return a valid compiled string.
  4. Verify preprocessor dependencies and plugin configurations in avenx.config.json.

Incorrect

/* Invalid SCSS syntax inside <@css> block -> Triggers AVX_W26 */
<@css>
card {
color: #333
/* Missing semicolon and closing brace */
</@css>

Correct

/* Valid SCSS syntax */
<@css>
card {
color: #333;
&:hover {
color: #6366f1;
}
}
</@css>

Custom Preprocessor Error Handling Example

// Custom preprocessor hook in avenx.config.js
module.exports = {
style: {
preprocessor: (code, filename) => {
try {
return customTransform(code);
} catch (err) {
console.error(`Preprocessing failed for ${filename}:`, err);
throw err; // Re-throw to allow compiler to handle AVX_W26 reporting
}
},
},
};

Warning Message

Multiple <state> tags found in component template. Only the first <state> tag will be processed; subsequent <state> tags are ignored.

Cause: This warning is emitted during compilation when a single component template file contains more than one <state> tag declaration. Avenx-JS enforces a single <state> block per component to maintain predictable state initialization and scoping. When multiple <state> blocks are detected, the compiler parses properties from the first <state> tag and ignores all subsequent <state> tags.

This typically happens for a few common reasons:

  • Accidentally declaring separate <state> tags for different categories of properties instead of merging them.
  • Copy-pasting template code that includes another <state> block.
  • Splitting initial state and default values across multiple <state> tags.

Resolution: To resolve this warning:

  1. Consolidate all reactive property declarations into a single <state> block within the component template.
  2. Remove any duplicate or extra <state> tags.
  3. If necessary, organize reactive properties within a single nested object structure inside the primary <state> block.

Incorrect

<!-- Multiple separate <state> blocks -->
<state count="0" />
<state user="null" isLoading="false" />
<div>
<p>Count: {{ count }}</p>
</div>

The compiler emits AVX_W28 and ignores the second <state> tag, leaving user and isLoading uninitialized.

Correct

<!-- Consolidated into a single <state> block -->
<state count="0" user="null" isLoading="false" />
<div>
<p>Count: {{ count }}</p>
</div>

Complex State Object Example

For larger components with complex state requirements, group properties inside a single <state> tag:

<state
counter="0"
settings='{ "theme": "dark", "notifications": true }'
/>

Warning Message

WARNING: Circular dependency detected in component imports: {0}

Cause: This warning is emitted when the compiler detects a circular dependency in the component import graph. A circular dependency occurs when following component imports eventually leads back to a component that has already appeared in the current dependency chain. This can happen through direct imports (Component A imports Component B, and Component B imports Component A) or through longer dependency chains involving multiple components.

Resolution: To resolve this warning:

  1. Remove unnecessary component imports that create dependency cycles.
  2. Extract shared functionality into a separate component, utility, or shared module that both components can depend on instead of importing each other.
  3. Restructure component relationships so imports form an acyclic dependency graph.

Incorrect

Direct circular dependency:

comp-a.component.js
import CompB from './comp-b.component.js';
comp-b.component.js
import CompA from './comp-a.component.js';

Indirect circular dependency:

CompX
CompY
CompZ
CompX

Correct

Parent
Child

A one-way dependency does not create a circular import and will compile without this warning.

Defensive Example

When two components need the same functionality, move the shared logic into a separate module or utility instead of importing the components into each other. This keeps the dependency graph acyclic and avoids compiler warnings.

AVX_W30 — COMPILER_DUPLICATE_ID_ATTRIBUTE

Section titled “AVX_W30 — COMPILER_DUPLICATE_ID_ATTRIBUTE”

Warning Message

Duplicate static id attribute "{0}" detected in template of {1}. Static IDs must be unique and should not be used inside loops.

Cause: This warning is emitted when the compiler detects duplicate static id attributes within a component template. HTML requires id values to be unique within a document. This warning is also emitted when a static id attribute is used inside an <@for> loop, since each iteration generates another element with the same id.

Resolution: To resolve this warning:

  1. Ensure every static id value within the component is unique.
  2. Avoid using static id attributes inside <@for> loops.
  3. Use class or data-* attributes for repeated elements instead of static HTML id values.

Incorrect

Duplicate IDs:

<div id="user-card"></div>
<section id="user-card"></section>

Static ID inside a loop:

<@for(item in items)>
<div id="user-card">
{{ item.name }}
</div>
</@for>

Correct

Use unique IDs:

<div id="profile-card"></div>
<section id="settings-card"></section>

Use class or data-* attributes for repeated elements:

<@for(item in items)>
<div class="user-card" data-user-id="{{ item.id }}">
{{ item.name }}
</div>
</@for>
Code Default Message Cause & Resolution
[AVX_R01] Mount target selector “{selector}” was not found in the DOM. Cause: Missing container tag in index.html.
Resolution: Verify your index file has a matching tag like <div id="app"></div>.
[AVX_R02] Page “{name}” is not registered. Cause: Mapping route patterns to non-existent or un-compiled pages.
Resolution: Check spelling and verify page JS exists inside src/pages/.
[AVX_R03] Component “{name}” is not registered. Cause: Declaring a custom component tag (e.g. <MyButton />) without registering it.
Resolution: Import and register it inside src/main.app.js.
[AVX_R04] Circular dependency detected in computed property “{name}”. Cause: Computed getters reference themselves directly or indirectly.
Resolution: Refactor computed expressions so they do not reference their own keys.
[AVX_R05] Failed to evaluate computed property “{name}”. Cause: Unhandled exceptions inside custom getter scripts.
Resolution: Review expression syntax and ensure referenced states are defined.
[AVX_R06] Navigation guard denied transition. Cause: A guard returned false (Expected behavior for access controls).
[AVX_R07] Navigation guard threw an error. Cause: Route guard evaluations failed.
Resolution: Wrap asynchronous fetches in try/catch blocks.
[AVX_R08] Failed to render interpolation expression “{expr}”. Cause: Accessing properties on undefined or null properties.
Resolution: Guard properties in template: {{ state.user ? state.user.name : '' }}.
[AVX_R09] Event handler execution failed. Cause: Unhandled exceptions in event listener actions.
Resolution: Verify method declarations match event expressions.
[AVX_R10] Bridge “{0}” is already registered. Available bridges: {1}. Suggestion: {2} Cause: An attempt was made to register a global bridge using a name (app.registerBridge(name, data)) that has already been registered on the AvenxApp instance. Bridge names must be unique across the application.
Resolution: Assign a unique string identifier to each bridge, or check if the bridge is already registered (app.hasBridge(name)) before calling app.registerBridge().
[AVX_R11] STATE_MUTATION_IN_UPDATE: Synchronous state mutation detected during component update. Cause: Modifying reactive state synchronously inside a template expression, computed property, or onUpdate hook causes the runtime to re-trigger the same update cycle, resulting in an infinite update/render loop.
Resolution: Never mutate state directly inside templates or computed getters. If a side-effect state change is required after an update, defer it asynchronously (e.g. setTimeout(() => { this.state.value = newValue; }, 0)) or derive the value through a computed property instead.

| [AVX_R12] | Error in component “{name}” during lifecycle hook “{hook}”: {error} | Cause: An unhandled error was thrown inside a component lifecycle hook (onMount, onUpdate, or onUnmount).
Resolution: Wrap lifecycle hook logic in a try...catch block, inspect the hook implementation for bugs, and ensure asynchronous operations properly handle rejected promises. | | [AVX_R13] | DOM parsing failed due to malformed HTML. Parser error: {error}. HTML context: “{html}” | Cause: DOM parsing failed due to malformed HTML in component templates or dynamically rendered content (e.g., unclosed tags or mismatched elements).
Resolution: Verify your template HTML is well-formed. Ensure all elements are properly nested and all tags are closed. | | [AVX_R14] | ROUTER_GUARD_TIMEOUT: A route guard exceeded the configured timeout duration. | Cause: One or more sequential route guards returned promises that failed to resolve within the configured timeout period, causing navigation transitions to stall.
Resolution: Inspect route guard logic for unresolved or hanging promises. Optimize long-running asynchronous operations, ensure all promises properly resolve or reject, or adjust the guardTimeout configuration if longer execution times are expected. | | [AVX_R15] | SANDBOX_VIOLATION: A sandbox security violation occurred. | Cause: Template or runtime expressions attempted to access restricted properties such as __proto__, constructor, or prototype, or unauthorized global variables. This restriction prevents prototype pollution, template injection, and unauthorized global scope access.
Resolution: Restrict expressions to authorized variables only. Avoid accessing or modifying prototype-related properties and unauthorized globals. If necessary, wrap values securely before exposing them to expressions. | | [AVX_R16] | Cannot reassign component state directly. | Cause: Assigning a new object to this.state, such as this.state = { count: 1 }, replaces the reactive Proxy and breaks change detection.
Resolution: Mutate properties on the existing state object instead, such as this.state.count = 1, or update several properties with Object.assign(this.state, { count: 1 }). | | [AVX_R17] | BRIDGE_CONSTRUCTION_FAILED: Failed to construct bridge “{name}”. {error} | Cause: An error occurred while constructing a registered bridge. This can happen when the bridge class’s constructor throws an exception, when required dependencies are missing, or when the bridge definition is malformed.
Resolution: Check the bridge class constructor for errors. Ensure all dependencies are properly imported and initialized before the bridge is registered. Verify the bridge definition follows the expected structure (extends AvenxBridge or conforms to the bridge interface).