2026-02-10

v10.32.1

Summary
  • Add top-level init{} blocks for configuration lifecycle tasks

  • Add stop action for halting AAA pipeline execution while preserving the current result

  • Management UI logs view now displays and supports filtering by structured log fields

  • Add reply action for sending RADIUS responses immediately while continuing pipeline execution

  • Add cache.increment() Lua method for atomic counter operations

  • Add /api/v1/caches/summary endpoint and /app/caches UI page

  • Documentation sidebar now displays hierarchical tree navigation with collapsible sections

  • Added full-text search to the management UI and documentation site with indexing and result highlighting

  • Management UI now displays TimeSpent metrics as per-request averages in dedicated charts

  • Automatic loading of default RADIUS dictionary when no dictionary is configured

  • Improved dashboard accessibility for monitor users with dedicated API endpoints and streamlined layout

  • Fixed configuration editor showing unwanted color preview boxes for hex values

  • Added short form syntax for the try action to simplify error-to-ignore conversion

  • Parser warnings now use structured logging instead of direct stderr output

  • Added new count filter to return the number of values in a multivalue

  • Improved policy selection to try the next policy when no matching handler is found

  • Add aaa.caught_errors variable to track all errors caught by try actions

  • Added warnings for policies and handlers without conditions blocks

  • Add support for named RADIUS constants in configuration conditions for clearer, more maintainable configs

  • Fixed template and configuration file contents not updating when switching between items

  • Configuration import and export now support filtering by content type (db, tls, lua, templates, licenses, management, ui-settings)

  • SQLite database auxiliary files are now excluded from configuration operations

  • Added server-side template rendering for configuration templates.

  • Added CLI template rendering via the template render subcommand.

  • RADIUS backend now supports independent queries for sending custom RADIUS requests from any protocol handler

  • The unsaved changes dialog now includes a Save button, and the template form's submit button was renamed from Update to Save for consistency

  • Add experimental servers and backends configuration viewers to the Management UI

  • Fixed file upload fields not working correctly when nested two or more levels deep in template groups

  • Fixed spurious 404 error notifications when template file_upload fields specify paths that don't exist yet

  • Added favicon to the Management UI

  • Add short form syntax for single-line modify statements

  • Add optional random jitter parameter to sleep action for retry logic and load testing

  • Management UI sessions are now preserved across API-initiated server restarts

Top-Level Init Blocks

Top-level init{} blocks allow you to execute pipeline actions when configuration is loaded or reloaded. Multiple init blocks can be defined and execute sequentially in the order they appear in the configuration.

Key Features:

  • Executes on initial configuration load and every subsequent reload/restart
  • Multiple blocks supported - they execute in order
  • Variables are isolated to each init block
  • Cache is shared across all init blocks within the same execution
  • Useful for logging, cache initialization, and resource setup

Documentation:

  • init - Complete reference with examples

Example:

init {
    log "SYSTEM" {
        json {
            "event" "configuration_loaded";
            "timestamp" datetime.timestamp;
        }
    }
}

Stop Action

New stop action halts pipeline execution immediately without changing the current result. This allows explicit control over pipeline flow by preventing subsequent actions from running.

Example

accept;
stop;
reject;

In this configuration, the pipeline accepts the request and stops. The reject action never executes, so the final result is accept.

Documentation

Display structured log fields

The Application Logs view in the Management UI now automatically detects and displays structured fields from log entries as additional columns. These dynamic columns are sortable and filterable, making it easier to analyze logs with custom context fields.

Reply Action

New reply action sends the RADIUS response immediately without waiting for the rest of the pipeline to complete. This enables fast acknowledgment of requests while performing background processing such as database writes, logging, or dynamic authorization.

Example

accounting {
    # Send reply immediately
    reply;

    # Background processing - client already received response
    backend {
        name "SQL";
        query "INSERT_ACCOUNTING";
    }
}

The reply action is useful in accounting pipelines where quick acknowledgment improves client behavior, and in scenarios where post-reply actions like dynamic authorization requests should not delay the response.

Documentation

Cache Increment for Atomic Counters

A new cache:increment() method has been added to the Lua cache API for atomic counter operations. This is particularly useful for implementing rate limiting, request counting, and other scenarios requiring atomic integer operations.

The method returns the new value after increment and is atomic and thread-safe. Cache timeout behavior now implements fixed window semantics where timeouts are only set when a key is first created or explicitly provided.

See scripts.context.cache for documentation and examples.

New Cache Summary Endpoint and UI

A new Management API endpoint GET /api/v1/caches/summary provides an overview of all configured caches, including:

  • Cache name
  • Current key count
  • Default timeout

The Management UI now includes a /app/caches page displaying this information in an interactive table with formatted timeout values.

Breaking Change: Inline Lua Script Syntax

The syntax for inline Lua scripts has changed from content { ... --END } blocks to triple-quoted strings (content """...""";).

Old syntax (no longer supported):

lua "example" {
    content {
        local context, previous = ...
        return previous
        --END
    }
}

New syntax:

lua "example" {
    content """
        local context, previous = ...
        return previous
    """;
}

The new syntax uses Python-style triple-quoted strings which automatically remove common leading indentation. This eliminates the need for the --END marker and provides cleaner, more readable inline scripts.

Migration

Update any inline Lua scripts in your configuration files:

  1. Replace content { with content """
  2. Remove the --END marker
  3. Add closing """;

See scripts for updated documentation and examples.

The management UI and documentation site now includes a full-text search feature accessible from the toolbar.

Features

  • Full-text search: Search across all documentation pages including articles, configuration references, and action documentation
  • Smart result previews: Search results show contextual previews with matched terms highlighted
  • Page highlighting: When navigating to a search result, matched terms are highlighted on the target page with a visual flash animation
  • Keyboard support: Navigate the search matches with cursor keys and enter. Press Escape to clear search highlights on any target page

TimeSpent displayed as per-request average

The Management UI statistics charts now show TimeSpent values as per-request averages instead of cumulative totals. TimeSpent data is displayed in a dedicated chart below the main handler statistics chart for clearer visualization.

When using time bucket aggregation on TimeSpent charts, values are averaged rather than summed, which is more meaningful for latency metrics.

Default Dictionary Loading

When no dictionary configuration is present, the server will automatically attempt to load the default RADIUS dictionary from /opt/radiator/server/dictionary. If the file does not exist, the server continues to operate without a dictionary.

Short Form try Action

The try action now supports a short form syntax that makes it easier to convert errors to ignore results without needing a full try/catch block.

Structured Parser Warnings

Parser warnings in configuration files (including deprecation warnings) are now emitted through the structured logging system instead of being written directly to stderr.

  • Warnings include proper log levels and can be filtered like other log messages
  • Location information is included as a structured field
  • Warnings integrate with existing log collection infrastructure

Log Output Format

When parser warnings are detected, they are logged at the WARN level with the following fields:

  • warning_message: The specific warning message
  • location: File path and line number where the issue was found

Disabling Parser Warnings

To suppress parser warnings, set the environment variable:

RADIATOR_PARSER_WARNINGS=0

Improved Policy and Handler Selection

When no explicit policy is specified, the policy selection logic now considers both the policy conditions and handler conditions together. If a policy matches but none of its handlers match, the system will now continue to try the next policy instead of failing immediately.

This change improves flexibility in configurations with multiple policies where handlers have restrictive conditions. Previously, if the first matching policy had no matching handler, the request would fail even if another policy could have handled it successfully.

Behavior Change

ScenarioPrevious BehaviorNew Behavior
First policy matches, no handler matchesError: "No handler found for policy"Tries next policy
No policies have matching handlersError: "No handler found for policy"Error: "No matching policy with handler found"

When a specific policy is explicitly selected (via policy_id), the behavior remains unchanged - if no handler matches within that policy, an error is returned.

Example Configuration

aaa {
    policy "SPECIALIZED" {
        handler "SPECIAL_AUTH" {
            conditions all {
                aaa.identity == "special-user";
            }
            @execute {
                # Handle special user
            }
        }
    }
}

aaa {
    policy "DEFAULT" {
        handler "DEFAULT_AUTH" {
            @execute {
                # Handle all other users
            }
        }
    }
}

With this configuration, requests for users other than "special-user" will now correctly fall through to the "DEFAULT" policy instead of failing when the "SPECIALIZED" policy's handler conditions don't match.

Error History Tracking with aaa.caught_errors

A new aaa.caught_errors variable is now available to track all errors caught by try actions during request processing. Previously, only the most recent error was accessible via aaa.caught_error. The new variable maintains a complete history of all caught errors.

Documentation

See try action documentation for more details.

Warnings for Policies and Handlers Without Conditions

The configuration parser now emits warnings when policies or handlers are defined without conditions blocks. This helps identify potential configuration issues where policies or handlers may be more permissive than intended.

Policy Without Conditions Warning

A warning is emitted when a policy has no conditions block, as all requests will match such a policy:

aaa {
    policy "TOO_PERMISSIVE" {
        # Warning: Policy 'TOO_PERMISSIVE' has no 'conditions' block.
        # All requests will match this policy.
        handler "AUTH" {
            @authentication { accept; }
        }
    }
}

Handler Without Conditions Warning

A warning is emitted when a handler has no conditions block, as all requests matching the policy will use that handler:

aaa {
    policy "EXAMPLE" {
        conditions all { true == true; }

        handler "HANDLER_1" {
            # Warning: Handler 'HANDLER_1' has no 'conditions' block.
            @authentication { accept; }
        }

        handler "HANDLER_2" {
            # Warning: Handler 'HANDLER_2' has no 'conditions' block.
            @authentication { reject; }
        }
    }
}

When Warnings Are Suppressed

To avoid noisy warnings in common valid configurations, warnings are suppressed in these cases:

  • Single handler with policy conditions: When a policy has conditions and only one handler, no warning is emitted for that handler (since the policy conditions already filter requests)

  • All handlers have conditions: When all handlers in a policy have their own conditions blocks, no warning is emitted for the policy itself (since the handlers provide the necessary filtering)

RADIUS Constants Support

Configuration conditions can now use named RADIUS constants for packet type codes instead of magic numbers, making configurations more readable and self-documenting.

Available Constants

Packet Type Codes:

  • radius.ACCESS_REQUEST, radius.ACCESS_ACCEPT, radius.ACCESS_REJECT
  • radius.ACCOUNTING_REQUEST, radius.ACCOUNTING_RESPONSE
  • radius.ACCESS_CHALLENGE, radius.STATUS_SERVER
  • radius.DISCONNECT_REQUEST, radius.DISCONNECT_ACK, radius.DISCONNECT_NAK
  • radius.COA_REQUEST, radius.COA_ACK, radius.COA_NAK

See Execution Context - RADIUS Constants for the complete list of available constants and their values.

Attribute Enum Values

For attribute enum values like Acct-Status-Type or Service-Type, use the radius.dict.* syntax which provides access to all dictionary-defined values:

# Instead of magic numbers, use dictionary values:
radius.request.attr.acct-status-type == radius.dict.Acct-Status-Type.Start  # 1
radius.request.attr.acct-status-type == radius.dict.Acct-Status-Type.Stop   # 2
radius.request.attr.acct-status-type == radius.dict.Acct-Status-Type.Alive  # 3
radius.request.attr.service-type == radius.dict.Service-Type.Login-User     # 1

Example Usage

Before:

if all {
    radius.request.code == 1;
} then {
    # What does 1 mean?
}

After:

if all {
    radius.request.code == radius.ACCESS_REQUEST;
} then {
    # Clear and self-documenting
}

Fixed a bug where navigating between different templates or configuration files in the management UI would show stale content from the previously viewed item.

Configuration import and export filters

Configuration exports and imports can now include or exclude specific content directories. This provides finer control over what is transferred when moving configurations between environments.

Export options:

  • includeDb - Database files (db/) - default: true
  • includeTls - TLS certificates and keys (tls/) - default: true
  • includeLua - Lua scripts (lua/) - default: true
  • includeTemplates - Templates (templates/) - default: true
  • includeLicenses - Licenses (licenses/) - default: false
  • includeManagement - Management configuration (management/) - default: false
  • includeUiSettings - UI settings (ui-settings/) - default: false

Import options:

The same content types can be controlled during import. Additionally, templates support three import modes via templateImportMode:

  • append (default) - Merge with existing templates
  • replace - Delete existing templates before importing
  • ignore - Skip template import entirely

Content that is not imported from the ZIP archive is automatically copied from the active configuration to preserve existing settings.

SQLite auxiliary files exclusion:

SQLite database auxiliary files (.db-wal, .db-shm, .db-journal and their .sqlite/.sqlite3 equivalents) are now automatically excluded from configuration exports, imports, directory listings, and backups. These are runtime state files that should not be transferred between environments.

  • Template rendering can be performed via CLI by running: radiator template render <TEMPLATE_FILE> <VALUES_FILE> [OUTPUT_FILE]
  • When OUTPUT_FILE is omitted, the rendered output is written to stdout.

RADIUS backend query support

The RADIUS backend now supports a query mode that allows sending independent RADIUS requests from any protocol handler. This enables issuing RADIUS requests from HTTP, TACACS+, or other protocols, not just from RADIUS request contexts.

See RADIUS backend configuration for complete documentation.

Experimental Servers and Backends Configuration Viewers

The Management UI now includes read-only viewers for Servers and Backends configuration. These are experimental features and subject to change in future releases. Both items are accessible from the Main section in the navigation drawer.

Nested Group File Upload Fix

Fixed an issue where file upload fields nested in two or more levels of groups would not properly associate uploaded files with the correct group instance. Previously, only single-level group nesting was correctly handled for file uploads. Now file uploads work correctly at any nesting depth.

Suppressed 404 Errors for Non-Existent Upload Paths

Template file_upload fields often specify directories that don't exist until files are actually uploaded (e.g., tls/custom-certs). Previously, the form would show error notifications when trying to list these directories. These errors are now suppressed since an empty directory listing is the expected behavior for new uploads.

Favicon

The Management UI now displays the Radiator logo as a favicon in the browser tab.

Fixed set action behavior

The set action previously used an insert-unless-exists strategy, meaning it would only assign a value if the target variable was not already set. This was inconsistent with the documented behavior and with the replace action.

The set action now unconditionally assigns the value to the target variable, correctly overriding any previously set value. This makes set and replace behave identically — both always override the current value.

Before (broken)

set vars.greeting "hello";
set vars.greeting "goodbye";
# vars.greeting was "hello" (second set was ignored)

After (fixed)

set vars.greeting "hello";
set vars.greeting "goodbye";
# vars.greeting is now "goodbye"

If you need the previous behaviour, use the modify action with the ?= operator:

modify vars.greeting ?= "hello";

Documentation

  • set — updated to clarify unconditional assignment behavior

Short form modify syntax

The modify action now supports a short form syntax for single-line assignments. Instead of requiring a block with curly braces, you can write the assignment directly after modify:

modify vars.foo = "bar";

This is equivalent to the block form:

modify {
    vars.foo = "bar";
}

The short form supports all assignment operators (=, ?=, +=) and improves configuration readability for simple cases. The existing block syntax remains fully supported for multiple assignments.

Documentation

Sleep Action Random Jitter

The sleep action now accepts an optional second parameter to add random jitter to the sleep duration.

Syntax

sleep <duration> <random>;

The actual sleep time will be duration + random(0, random) inclusive. This is useful for:

  • Adding jitter to retry logic to prevent thundering herd problems
  • Simulating variable network latency in tests
  • Load testing with realistic timing variations

Example

try {
    backend my_backend;
} catch {
    # Sleep 1s to 3s (1s base + 0-2s random)
    sleep 1s 2s;
    backend my_backup_backend;
}

Documentation

Sessions persisted across restarts

Previously, triggering a server restart from the management UI would invalidate all active sessions, forcing users to log in again. Sessions are now preserved across API-initiated restarts, so users remain logged in seamlessly.

Known Issues

When the /var/lib/radiator directory has 15_certificates.radconf file, and the file has not been edited once, the rpm package upgrade will show a warning warning: file /var/lib/radiator/15_certificates.radconf: remove failed: No such file or directory. The warning is harmless and can be ignored, as the 15_certificates.radconf file has been renamed.