Troubleshooting and Verification

Source and package versions

One AIWAF repository. Python: py/aiwaf/ · Node.js: js/ · Rust/WASM: rust/ · Java: java/. Source and canonical README. Versions shown describe the source checkout; package releases are independent. Current Python/Node source targets are aiwaf 1.1.8 (Python) and aiwaf 1.1.5 (npm), with Rust/Python 0.2.7 and WASM 0.2.5 and Java 1.3.5. Sandbox guides retain their separately pinned builds.

CLI rejects --app app.py

--app takes a Python import target, not a filename. For app.py containing app = Flask(__name__), run from its directory:

aiwaf init --framework flask --app app:app

For a factory use app:create_app. For Django use --framework django --settings project.settings. Install dependencies and load the application's configuration in the same environment; discovery imports the live application.

Manifest has only / and static routes

Confirm the imported file is your intended application, all blueprints/routers are registered, and the app factory finishes before discovery:

python -c "import app; print(app.__file__); print(*sorted(r.rule for r in app.app.url_map.iter_rules()), sep='\n')"

This diagnostic is for a Flask module-level app. Regenerate the manifest after registering additional routes. An unimported blueprint cannot appear in the live route table.

Website setup page returns 404

This documentation website is built with Jekyll and served as static files on GitHub Pages. Setup landing pages and short URLs use static redirect pages. Unknown pages use 404.html.

  1. Run the Jekyll build and check its output for missing includes or Liquid errors.
  2. Set the repository Pages source to GitHub Actions and inspect the Pages workflow for build or deployment failures.
  3. For a project site, verify that the deployed URL prefix matches baseurl. Navigation, assets, and browser search must use that prefix.
  4. Check that the latest successful workflow deployed the intended commit.
bundle exec jekyll build
python scripts/check_site.py
bundle exec jekyll serve

The website has no application workers, database, signup endpoint, or runtime health endpoint. SDK protection checks belong to your application and the runnable examples.

Normal traffic is blocked, or test traffic is never blocked

Compare response details and logs with the selected middleware, route plan, client IP, headers, and block/reputation state. A 403 may come from AIWAF or a proxy; avoid attributing it without evidence. Rate throttling can have different status semantics from a deterministic block.

Private clients, health paths, static paths, or route annotations may be exempt. Local curl success alone does not demonstrate protection for public clients. To exercise header validation, use a non-exempt route and a client context matching deployment; include representative User-Agent/Accept headers and browser-standard headers such as Accept-Language/Accept-Encoding in the normal case. The static documentation website does not run AIWAF middleware; exercise these checks against your protected application. Configure a small staging threshold and test below, at, and above the boundary. Do not disable protection globally to resolve a single route.

Client IP or multi-worker counters look wrong

Inspect address extraction for your adapter and the actual forwarding-header chain. Have the trusted outer proxy overwrite client-supplied headers. Java has explicit trusted proxy CIDRs; Python/Node resolution follows their own rules.

File persistence is separate from a shared rate cache. Redis configuration must resolve to an active shared backend. Flask rejects invalid Redis configuration at initialization; runtime Redis rate-cache failures return HTTP 503; test enforcement across two workers and examine initialization logs. Use the same rate-key prefix for workers sharing one service, and distinct prefixes for unrelated services.

Training produces no usable model

Verify that the trainer reads the actual log path/format, logs include response observations, minimum sample thresholds are met, and the output model is written where runtime inference loads it. Representative normal traffic is needed; forced training does not repair missing or malformed inputs. Inspect trainer/model help for the installed adapter:

aiwaf flask train --help
aiwaf flask model --help
# Django uses its management commands:
python manage.py detect_and_train --help

Python requires JSON model state. Regenerate legacy executable artifacts rather than renaming their extension. Verify model load diagnostics after deployment/reload. Models with different feature schemas or native formats need a supported conversion path or retraining.

Verification before publishing documentation

Render every page; check internal links, fragment anchors, setup redirects, and unknown-page behavior. Then test code samples with the installed runtime in a clean staging environment, including a normal request and an intentional rejection. Finally test the public URLs after deployment. These are separate checks.

See configuration, migration, and the runtime operations pages for the exact settings and supported tools.

Rust and CSV diagnostics

The explicit native pipeline fails startup if native API/schema/profile validation fails. Check for NativeCSVPipeline support in the deployed interpreter. Installing Rust does not switch a legacy chain to the new adapter. Unknown keys and legacy uppercase settings are invalid in the native profile; Rust-disable compatibility flags do not supply a fallback.

python -c "import sys, aiwaf_rust; print(sys.executable); print(aiwaf_rust.__file__)"
python scripts/check_native_csv_runtime.py

For retained legacy integrations, if installation succeeds but behavior stays on Python, check the application's interpreter, worker restart, extension capabilities, and AIWAF_USE_RUST/AIWAF_RUST_CSV. Framework settings take precedence over the standalone environment flag. Unicode/custom parser paths may deliberately use Python; ISO parsing does so by default because it measured faster.

A PHP probe returning 404 may be reaching an unprotected application. Verify the deployed WSGI import is the protected app (for example, from app import app as application), inspect registered request hooks, and check route/IP exemptions. A path missing from the route table is not automatically blocked: keyword, rate, and anomaly policies decide whether to deny it.

For Windows log-directory deletion failures, stop requests and close cached CSV log writers first. For HTTP 503 from rate limiting, check Redis availability or required native CSV capabilities. A freshly trained FastAPI model needs an explicit reload or application restart.

Existing CSV data is missing from the CLI

First compare the application's data directory with the directory printed by the CLI. A command launched from another working directory may select a different store. Pin the same absolute AIWAF_DATA_DIR, or use aiwaf flask --data-dir /absolute/path/aiwaf_data status. Python 1.1.4 fixes project and user-directory discovery and imports the older runtime format at startup.

For a legacy custom storage.file_path, /path/custom.csv maps to /path/custom/; a file named runtime_store.csv maps to its parent. The original file remains as a backup source. Policies now live in the shared files; runtime_metadata.csv retains frequencies and runtime history. Do not delete migration markers to make an old source active again: that can restore deliberately removed entries.

If startup reports an invalid legacy header, JSON value, or expiry, repair that source and retry after stopping old workers. See the migration guide for conflict handling and rollback.

Node dependency and native startup issues

Reproduce the committed dependency tree with npm ci and run the full npm audit. The current source fixes the earlier Jest/Fastify/NestJS advisory chains; an older lockfile can still install vulnerable versions. A deprecation notice or a blocked optional postinstall is not itself an audit result.

If native mode cannot find NativeRequestPipeline, inspect the installed aiwaf-wasm package, await the adapter's initialization, and verify that it matches the source API. Keep native profile options separate from legacy constructor options. Node's native event files are distinct from the Python policy schemas and legacy Node stores.

Jest's Must use import to load ES Module error can indicate a mismatch between the test dependency tree, Node version, and transform configuration. The repository uses patched NestJS 11 and a targeted cookie transform on Node 22. Retain that configuration when reproducing the source tests. See the tested dependency setup.

October 2026 release upgrade

The prepared source versions are Python 1.1.6, Rust/Python 0.2.5, Node.js 1.1.4, WASM 0.2.4, and Java 1.3.4. These are source targets; verify registry availability before installing. Python requires aiwaf-rust>=0.2.5, including the TrainingEvidence API. Node offline training requires the matching WASM receipt API.

  1. Back up policies, logs, models, and training evidence. Use the same absolute data and evidence directories for application workers and CLI trainers.
  2. Install the matching native companion before upgrading its host package: Rust before Python, WASM before Node. Preserve training_evidence.json and node_training_evidence.json across expiry, unblocking, restarts, and log rotation.
  3. Stop older file writers and restart all workers on the new code. Mixing old unlocked writers with new writers can still lose updates.
  4. In staging, train twice on identical logs, then verify handled evidence does not recreate a removed or expired block. Add genuinely fresh requests and confirm they must independently satisfy the enforcement threshold.
  5. Verify that listing and expiry checks preserve concurrently refreshed blocks and unrelated IPs. Check the raw expiry and backend location if entries disappear unexpectedly.

Java CSV and file storage

Java 1.3.4 reloads current storage under a shared JVM and OS sidecar lock for each operation. Reads filter expiry without rewriting disk; mutations preserve other instances' updates and report persistence failures. This adds file I/O. Java model training still does not add blocklist entries. Rate buckets and other per-engine memory state retain their existing isolation.

Lock recovery

Python training uses an OS file lock; Java CSV/file OS locks also release on process exit. Keep their stable sidecar lock files in place while workers run. Node uses lock directories for training and legacy CSV mutations; a crash can leave them behind. Confirm the owning process has stopped before removing a Node lock directory. Do not delete training receipts to clear a lock: doing so loses handled-evidence history.

Release checks

Local validation passed 247 Node tests across 67 suites with the coverage gate, 215 Java tests with 3 skips, and 38 Rust/WASM native tests. After the native dependency bump, 11 affected Python packaging tests passed through the appropriate Django and pytest runners. These checks do not replace full release CI, dependency audits, signing, or operating-system wheel builds. Build Linux/macOS Rust wheels using the release matrix; the local bundle contains a Windows x86-64 wheel.

For release maintainers: publish the WASM companion, refresh the Node lockfile from the registry to record its actual integrity, then run npm ci and the native integration checks. Do not substitute an older native dependency to satisfy a stale packaging test. See the changelog.