Overview
Troubleshooting & Best Practices
This page collects the most frequent symptoms on a WUIC installation, their real cause and the verified fix. Before digging into code, read the three diagnostic endpoints: most of the time the answer is there.
First diagnosis: three endpoints
| Endpoint | What it tells you | Fields to check |
|---|---|---|
GET /api/Meta/LicenseStatus | license state and machine fingerprint | licenseValid, licenseReason, tier, features, machineFingerprint, dataDbms, metaDbms |
GET /api/Meta/FirstRunStatus | whether the installation is still in first-run mode | firstRun |
GET /api/Rag/Health | state of the .NET RAG engine | status (ok / not-initialized), engine, lastError |
Frequent symptoms
Lists show at most 20 records
The backend runs in Trial mode: license missing, expired or with an unauthorized fingerprint. LicenseStatus returns licenseValid=false with the reason in licenseReason (invalid_signature, machine_fingerprint_not_authorized, machine_fingerprint_missing, license_expired). Fix: see the Licensing page; after entering license-payload and license-signature restart the backend and check licenseValid=true.
A Pro feature opens the "access denied" page
The license tier does not include the feature (features in LicenseStatus): designer, workflow, reports, spreadsheet, pivot-grid and RAG chatbot are Professional. The route guard requireFeature blocks access on Developer.
"RAG server unreachable" / RAG offline
status=not-initializedwithoutlastError: the engine is downloading models and index (~4.5 GB, 1-5 min) or loading them (warm-up ~30 s). Wait for the in-app notification.lastErrorset: download failed (CDN unreachable, disk full) orrag-engine/WuicRagEngine.dllmissing. Checkrag-engine-models-url, disk space andrag-engine-dll-path.rag-use-dotnet-engine=falsewithout a Python server: the controller bridges to127.0.0.1:8765, which does not exist. Set the key back totrue.- Slow queries (15-25 s): normal on CPU. With an NVIDIA GPU check CUDA 12.x + cuDNN 9 and
rag-engine-cuda-path. - Slow cold start on Windows: add
rag-engine/artifacts/to the antivirus exclusions (Defender scansvectors.npyon every start).
Metadata changes are not visible
The runtime metadata cache is still valid. After direct SQL changes to the _metadati__* tables call MetaService.invalidateMetadataRuntime with the explicit body {"clearAll":true} (without a body the flush is partial) and check that projectMetadataVersion changes via MetaService.getProjectMetadataVersion. Changes made from the designer or the chatbot invalidate by themselves.
Every query longer than a few seconds fails
AppSettings.autoGeneratedQueryTimeout is the timeout in seconds of the auto-generated queries: a value that is too low (e.g. 1) fails any non-trivial list. Set it back to 30 or more; the key is hot-reloaded.
"Optimistic concurrency error" on save
The record was modified by another user or process after it was read: reload it and reapply the change. If it appears on every write, check that there are not two backends on the same database (typical in test: one started by hand plus the dispatcher's). See Optimistic Concurrency.
The session is closed by itself (session_replaced)
The framework enforces a single session per user: a second login of the same user replaces the first one. If it happens without a second login, again: two backends on the same metadata DB.
The first-run wizard reappears on every start
AppSettings.firstRun is still "true" in the appsettings.{Environment}.json read by the running host (mind the active environment: Development vs Production). The wizard sets it to false at the end of provisioning; if the file is not writable by the process, it stays true.
A lookup shows [object Object]
mcuilookupdata_value_field, mcuilookupdata_text_field and mc_ui_grid_*_id_field must hold the friendly column name (= mc_nome_colonna): they are keys into the response JSON. Fields that emit SQL (md_nome_tabella, mc_real_column_name) must instead carry the exact physical case of the schema.
The query-string filter is ignored
URLs to <route>/List accept filterInfo=..., not filter=....
Routes with spaces are not found
Metadata routes may contain significant spaces: do not trim() or normalize them when building or comparing them.
Error 10316 during tutorial scaffolding
SQL Server 2017, or Express with its RAM cap, under spatial load. Requirement: SQL Server 2019+; for local dev use Developer Edition or LocalDB.
Linux behind a reverse proxy: wrong port or scheme in URLs
The nginx vhost must forward host and scheme: proxy_set_header Host $http_host; and proxy_set_header X-Forwarded-Proto $scheme;. Upgrades do not rewrite an existing vhost.
Linux: connections refused with hundreds of users
With the defaults of nginx and of the databases (nginx 768 connections per worker, MySQL 151 connections, PostgreSQL 100, Oracle Free 200 processes) the server refuses connections before the application is busy: nginx's error.log shows worker_connections are not enough, the application log shows Too many connections (MySQL), 53300: sorry, too many clients already (PostgreSQL) or ORA-12516 / ORA-00020 (Oracle). The Linux installer raises these limits: nginx 4096 connections per worker with keep-alive towards Kestrel, MySQL and PostgreSQL 300 connections and buffers at 25% of the RAM, Oracle 400 processes. An installation made with an earlier installer keeps the old values: the commands to raise them by hand are in scripts/linux/README.md, section "Capacity for hundreds of concurrent users". SQL Server Express stays capped at 4 cores and about 1.4 GB of buffer pool, whatever the server.
Reports not generated on Linux
Versions before 1.7.0 handled fonts through a Windows-only graphics library: update the package.
Login refused after many attempts (HTTP 429)
The login answers 429 errors.auth.login_rate_limited: the login attempt limit was hit, and retryAfterSeconds says how many seconds to wait. There are two causes:
- Same user: 5 wrong passwords in 5 minutes lock that user for 1 minute. Wait the minute; a successful login resets the counter. This limit cannot be turned off.
- Many logins from the same IP (stress tests, an office behind a shared NAT): it applies only if
loginRateLimitPerIpPerMinuteis greater than0, and locks the IP for 1 minute. Raise the value, or add the IP tologinRateLimitExemptIps(e.g.10.0.2.2for a VirtualBox VM in NAT, which sees the host at that address). Up to 1.7.15 the per-IP limit was fixed at 30 attempts per minute and the only exception was loopback.
See Authentication & Authorization.
Quick checklist
1. Network tab: request and response of the failing MetaService.* call. A wrong JSON key does not return 400: the backend uses defaults and the diagnosis is skewed.
2. Route md_props_bag and column configuration (mc_ui_column_type, lookups, hide flags).
3. LicenseStatus, FirstRunStatus, Rag/Health as above.
4. The appsettings.{Environment}.json of the environment that is actually active.
5. One backend per database.
Best practices
- Primary keys and indexes on exposed tables: auto-generated filters, paging and sorting rely on them.
- Change metadata from the designer or the chatbot when you can: cache invalidation is automatic.
- Enable
AppSettings:enablePerformanceInspectorto measure fetch and render per route (average, p95, max) before optimizing by guesswork. - After an upgrade compare
appsettings.jsonwith the package template: new keys have conservative defaults, but the comparison avoids surprises. - Use typed exceptions for application errors: see Custom Exception Handling.