Operations and Troubleshooting

Deployment checklist, failure diagnosis, and validation guidance for the Enezaframework dashboard system. Part of the Dashboards series.

Table of Contents

  1. Deployment Checklist
  2. Diagnostic Order
  3. Troubleshooting Matrix
  4. Symptom: The Report Is Missing from the Data-Source List
  5. Symptom: unknown_report or "not a registered dashboard data source"
  6. Symptom: Field, Measure, or Aggregation Not Available
  7. Symptom: Chart Requires Series, Line, or Size
  8. Symptom: Table or Preview Columns Rejected
  9. Symptom: Layout Validation Errors
  10. Symptom: Unknown Parameter or Filter Field
  11. Symptom: Widget Is Empty
  12. Symptom: Published Dashboard Is Not Visible
  13. Symptom: Seeding Skips or Overwrites Work
  14. Symptom: Designer Access Denied
  15. Symptom: Comparison Shows a Dash
  16. Error Codes
  17. User Validation Checklist
  18. Related Guides

Deployment Checklist

Run these steps in order when deploying dashboard or report changes.

  1. Install and migrate the apps: enezadashboard, enezareporting, and the business modules that define dashboards.
  2. Import report modules at startup so report classes register.
  3. Validate definitions: bash python manage.py seed_dashboards --dry-run --json
  4. Seed definitions: bash python manage.py seed_dashboards
  5. Sync RBAC: bash python manage.py rbac_sync
  6. Grant permissions for report outputs and the dashboard manage action.
  7. Restart the application process if report code changed, so the process-local discovery cache is rebuilt.
  8. Verify /dashboards/<module>/ for a real user, including a user without the designer action.
  9. Check that drafts did not accidentally replace published versions.

Do not skip the dry run. It catches missing reports, invalid layouts, unknown widget types, and bad parameter names before the database changes.


Diagnostic Order

When a dashboard is broken, work from the data outward:

flowchart LR
    A[Is the report registered?] --> B[Is it eligible?]
    B --> C[Does the user have output permission?]
    C --> D[Does the widget config match metadata?]
    D --> E[Does the draft pass publication?]
    E --> F[Is the dashboard published and visible?]

Most failures are at the first three steps, not in the renderer.


Troubleshooting Matrix

Symptom Most likely cause Fix
Report absent from the data-source list Not opted in, not registered, ineligible, or wrong app label. See the dedicated section.
Widget says report is unknown report_ref is stale or the code changed. Update the reference, clear the discovery cache, re-publish.
Widget says forbidden Missing output.*.view permission or report test_func. Run rbac_sync, grant permission, re-check the report's access function.
“Measure is not available” Field is not a report column/alias, or the widget uses the wrong name. Use canonical metadata names.
“Chart value field must be a numeric measure” The field is text or not a measure. Choose a numeric/computation measure.
“This chart type requires a series field” Stacked/heatmap chart missing series_field. Add a dimension.
“A bubble chart requires a size field” Missing or non-measure size_field. Add a numeric measure.
“Table column … is not available” Column not in the report. Add it to columns or remove it from the widget.
“Widget width must be between 2 and 12” Invalid layout. Correct x, y, w, h.
“Unknown report parameter” Parameter not in the report's parameter_spec. Use an allowed name or remove it.
“Filter field … is not available” Filter field not exposed by the report. Enable use_query_builder and expose the field; or remove the filter.
Widget is empty Period, entity scope, filters, or no data. See Widget is empty.
Published dashboard returns 404 Not active/published, no published version, access code, or module access. See Published dashboard is not visible.
Designer returns 403 Missing action.enezadashboard.manage. Run rbac_sync and grant the action.
Seed skips a dashboard It is admin-owned. Use --force or take ownership intentionally.
Seed overwrote browser edits The dashboard is seed-owned. Take ownership before editing in the browser.
Seed removed tabs/widgets Prune is on by default. Use --no-prune or include them in the definition.
Comparison shows “—” No comparison period, report has no date, or previous value is null/zero. See Comparison.
View report link is missing report_url_name is empty or cannot reverse. Register the URL or correct the name.
New report code not visible Process-local metadata cache. Restart or call clear_dashboard_report_cache().

Symptom: The Report Is Missing from the Data-Source List

Work through these checks in order.

1. Is dashboard_enabled set?

python
class SalesReport(TabularReportView):
    dashboard_enabled = True

Without it, no dashboard surface shows the report.

2. Is the class imported at startup?

Registration happens when Python defines the class. If the module is never imported, it never registers. Check:

  • myapp/views/__init__.py imports the report module;
  • myapp/urls.py imports the class;
  • the app is in INSTALLED_APPS.

3. Is the report type supported?

Only TabularReportView, SummaryReportView, and DetailedReportView are supported. Crosstab, time-series, document, and drill-down reports are excluded in v1.

4. Does the report resolve a model?

report_model must be a model class, or get_report_model() must return one. A report with no model is ineligible.

5. Do the columns parse?

A malformed column list makes the report ineligible. Test it through the metadata endpoint or a shell call:

python
from enezareporting.dashboard import get_dashboard_report_source

source = get_dashboard_report_source("myapp.salesbyitem")
print(source.meta.columns)

If parsing fails, the source is not returned and the error reason is internal. Fix the column definition first.

6. Is the report in the same app as the dashboard module?

The widget editor's report dropdown is filtered by the dashboard's module:

python
list_dashboard_report_sources(app_label=module or None, ...)

That means a dashboard owned by module myapp only offers reports whose model app label is myapp when you pick a report in the widget form. The current value is always kept in the choices for editing, and a seeded definition can reference a report from another app, but editors will not see that report as a new option (enezadashboard/forms.py:694-702).

The create form's initial data-source list is not module-filtered, so a report may appear during creation even though it will not be offered later in the widget editor.

If you need cross-app reporting, create the dashboard in the report model's app, or seed the widget definition with the cross-app report_ref.

7. Does the user have the output permission?

list_dashboard_report_sources(user=..., request=...) filters by output.<app_label>.<report_slug>.view. Run rbac_sync and grant the permission.

8. Is the discovery cache stale?

Discovery is cached per process. After changing report code:

python
from enezareporting.dashboard import clear_dashboard_report_cache

clear_dashboard_report_cache()

or restart the process.

9. Is the code duplicated?

Two reports with the same report_ref raise ImproperlyConfigured during discovery. This usually appears as a 500 on the designer page. Make one code unique or set an explicit dashboard_code.

10. Is it a URL problem only?

A report with an empty or unreversible report_url_name is still eligible. Only the View report link is blank. Do not confuse that with a missing data source.


Symptom: unknown_report or "not a registered dashboard data source"

This means a widget, definition, or request used a code that discovery does not know.

Check Action
Typo in report_ref Compare with discover_dashboard_reports() keys.
dashboard_code changed Update every widget and definition that references the old code.
Report renamed The default slug follows the class name; rename changes the code unless report_slug/dashboard_code pins it.
Report not imported Import it at startup.
Report ineligible Fix opt-in, type, model, or columns.
Cache stale Clear the discovery cache or restart.

After correcting references, re-run the seeder or update the draft in the designer and publish.


Symptom: Field, Measure, or Aggregation Not Available

Dimensions

A widget dimension must be a parsed report column. The most common cause is a group_by field that is not in columns:

python
group_by = "item_code", "item_description"
columns = ["item_code", SumItemQuantity]   # item_description missing

Here item_description cannot be a chart category or table column. Add it to columns.

Measures

A measure must be:

  • a computation field, or
  • a numeric model field that appears in columns.

Text, date, boolean, and relation fields are not measures. A chart value_field must be in meta.measures specifically (enezadashboard/widgets/chart.py:76-80).

Aggregations

  • Numeric model fields: sum, avg, min, max, count.
  • Computation fields: only their own method name, usually sum.

If you ask a Sum computation field for avg, validation reports that the aggregation is not supported. Create a separate Avg computation field instead.

Names

Use the canonical column name:

text
sum__item_quantity

The class attribute SumItemQuantity is exposed as an alias and may work, but canonical names are stable across refactors.


Symptom: Chart Requires Series, Line, or Size

These are structural requirements, not optional polish:

Chart type Required extra field
heatmap, stacked_bar, stacked_area series_field (dimension)
combo line_field (measure)
bubble size_field (measure)
scatter, bubble numeric category_field
gauge measure or value_field, plus optional target/scale_max

The requirement matrix is in Dashboard Reference — Chart.

If the field exists in the report but is not offered, check that it is in columns.


Symptom: Table or Preview Columns Rejected

  • Every configured column must be a report column or alias.
  • Leave columns empty to use the first six report columns.
  • page_size must be between 1 and MAX_PAGE_SIZE (default 100).
  • row_limit must be between 1 and MAX_PREVIEW_ROWS (default 20).

A preview is not paginated; it is a short table. If you need paging, use a table widget.


Symptom: Layout Validation Errors

Publication validates:

  • x >= 0, y >= 0;
  • w 2–12;
  • h 2–8;
  • x + w <= 12.

The drag endpoint additionally caps x at 11 and y at 200 (enezadashboard/views/designer.py:645-654).

Common fixes:

python
{"x": 9, "y": 0, "w": 3, "h": 2}    # valid KPI at the right edge
{"x": 6, "y": 0, "w": 6, "h": 4}    # valid half-width chart
{"x": 8, "y": 0, "w": 6, "h": 4}    # invalid: x + w = 14

If a definition omits layout, the seeder applies a type default. Do not rely on that for a deliberate composition; set the coordinates.


Symptom: Unknown Parameter or Filter Field

Unknown parameter

parameter_config keys must be allowed by meta.parameters:

  • DateRangeParam → start_date, end_date;
  • other parameters → their name and form_fields.

Remove or rename the key. A parameter that exists in the report's form but is not declared in parameter_spec is not allowed.

Unknown filter field

filter_config rules must use IDs from meta.filter_fields. These come from get_report_filters_by_model() and require use_query_builder = True.

If meta.filter_fields is empty:

  1. set use_query_builder = True on the report;
  2. confirm the report's filter metadata method returns fields;
  3. re-check the metadata endpoint;
  4. clear the discovery cache if you just changed the report.

Operators must be supported by the workflow engine. Use equal as the safe default.


Symptom: Widget Is Empty

Work through the data path:

  1. Period — the dashboard defaults to the site DEFAULT_PERIOD (last_30_days unless overridden). A tab or dashboard may set a narrower range. Try All/a wider custom range.
  2. Reference date field — if the chosen field has nulls or is not the field the user expects, the period may exclude all rows. Use the report's date_field or a populated date field.
  3. Entity scope — dashboard_entity_scoped filters to request.current_entity. A user with no current entity or a different entity sees fewer rows.
  4. Page filters — remove user filters and admin filter_config rules to isolate.
  5. Report data — the underlying model may simply have no records in range.
  6. Permissions — a forbidden report shows an error rather than an empty widget; do not confuse the two.
  7. Grouping — a report grouped by a field that is empty produces blank categories. Check the underlying data.

If the widget displays “This widget could not be loaded”, the renderer caught an unexpected exception. Check the enezadashboard server log; the UI deliberately hides details (enezadashboard/services/renderer.py:874-892).


Symptom: Published Dashboard Is Not Visible

dashboard_is_visible() requires all of:

  • is_active = True;
  • publication_status = "published";
  • published_version is not null;
  • the module exists and the user can access the module menu;
  • when access_code is set, the user has that permission.

Source: enezadashboard/services/access.py:40-57.

Checklist:

  • [ ] The dashboard was published, not just saved as a draft.
  • [ ] published_version points to a version.
  • [ ] is_active is true.
  • [ ] access_code is empty or the user has it.
  • [ ] The module exists and the user can access its module menu.
  • [ ] At least one tab has an active widget.

A module with no visible dashboard shows the No dashboard designed state rather than falling back to a list page. That is expected behavior.


Symptom: Seeding Skips or Overwrites Work

Skipped

The dashboard is managed_by = "admin". Seeding protects administrator work. Use --force only when you intend to overwrite it:

bash
python manage.py seed_dashboards --dashboard <code> --force

Overwritten

The dashboard is managed_by = "seed". Browser edits are not protected. Take ownership in the designer before making persistent edits, or move the change into the definition.

Tabs/widgets disappeared

Prune is on by default. A definition that omits a tab or widget deletes it from the draft. Use --no-prune for partial definitions.

Default conflict

Only one active default per module is allowed. If another administrator-owned dashboard is the default, seeding raises default_conflict unless forced. Resolve ownership or clear the other default deliberately.

Duplicate definition

Two sources define the same (module, code). load_definitions() raises ValueError. Keep one source of truth.

“No dashboard definitions found”

  • The app config does not expose dashboards.
  • The settings list is empty.
  • --module or --dashboard filtered everything out.
  • The module is not installed.

Data settings did not apply

data_settings (reference_date_field, limit, default_period) is not part of the seed schema. Set it in the designer dashboard form. If it must be code-controlled, extend the seeding service rather than adding an ignored key.


Symptom: Designer Access Denied

The designer requires:

  • an authenticated session;
  • the RBAC action action.enezadashboard.manage.

Fix:

bash
python manage.py rbac_sync

Then grant the action to the appropriate role. The action is registered at app startup (enezadashboard/apps.py:9-16) and enforced before every designer view (enezadashboard/views/designer.py:153-160).

If the page loads but the data-source list is empty, this is a report permission problem, not a designer action problem.


Symptom: Comparison Shows a Dash

KPI comparison and line/area comparison require:

  1. a resolved current period with a start and end;
  2. a comparison choice of previous or previous_year;
  3. a report with date support (DateRangeParam or a resolvable reference date);
  4. a non-null, non-zero previous value.

Only KPI and line/area charts support comparison (enezadashboard/services/renderer.py:604-619).

A dash is normal when the previous value is null or zero; the delta is undefined.


Error Codes

Code Surfaces in Short fix
invalid_config Widget validation, publication Correct the widget config.
unknown_report Widget render, definition validation Fix report_ref; clear the cache.
report_forbidden Widget render Grant the output permission; run rbac_sync.
report_not_eligible Report execution Fix opt-in, type, model, or columns.
invalid_parameters Report execution Use allowed parameter names and values.
invalid_filter Report execution Use allowed filter fields/operators.
filters_not_supported Filter validation Set use_query_builder = True or remove the filter.
filters_unavailable Filter validation Install/configure the workflow filter engine.
invalid_date_field Period override Choose a real date field.
unsupported_aggregate KPI aggregate Use a supported computation/numeric field.
invalid_data Chart render Remove negative values or change chart type.
query_failed Widget render Inspect the server log.
no_draft Publish Re-open the designer to create a draft.
publish_invalid Publish Fix the listed tab/widget errors.
invalid_default Default action Publish and activate the dashboard first.
invalid_definition Seeding Fix the definition errors from dry-run.
default_conflict Seeding Resolve the other module default or use --force.
unknown_wireframe Create/apply wireframe Use a valid wireframe code.

Full descriptions are in Dashboard Reference — Error Codes.


User Validation Checklist

The user is responsible for all validation. A reasonable manual pass:

  • [ ] The report appears in discover_dashboard_reports().
  • [ ] The metadata endpoint returns JSON with the expected dimensions and measures.
  • [ ] The report appears in the widget editor for the dashboard's module.
  • [ ] A user with the output permission sees widget data.
  • [ ] A user without it sees a permission error, not the rows.
  • [ ] The dashboard is published, active, and visible at /dashboards/<module>/.
  • [ ] Draft edits do not change the published page.
  • [ ] Publishing validates and creates a new draft.
  • [ ] Seeding is idempotent: a second run reports no duplicates.
  • [ ] --dry-run catches an intentionally broken definition.
  • [ ] The module entry selects the expected preferred/default dashboard.
  • [ ] Period and comparison controls change KPI and chart values as expected.
  • [ ] Table paging and sorting work within configured limits.

Per project rules, the agent does not run tests and does not claim that any of these pass.