Troubleshooting
v0.0.1
This page lists the compile messages Gervaz raises, the symptoms you see at run time, and the DSL options that the built-in templates and handlers do not read. Every compile message is a Spark.Error.DslError from a verifier. Spark prints it as a compile warning, so a plain mix compile carries on. Run mix compile --warnings-as-errors to make a message fail the build.
Table compile messages
| Message | Cause | Fix |
|---|---|---|
identity section is required, identity.name is required, identity.route is required | The table has a column, filter, row action or bulk action, or sets a route, and the identity is missing a part. | Add identity do name :posts; route "/admin/posts" end. |
Missing required table source action(s): ... | read is always required. get is required when row.selectable is true, when there is any bulk action, and for row actions of type :destroy, :update, :unarchive, :permanent_destroy or :accordion. destroy is required when a :destroy action exists. :edit, :event and :link need no get. | Declare the actions on the resource or the domain. See Table identity and source DSL. |
... table names actions the resource does not have: ... | A read, get, destroy or archive action named on the resource, or inherited from the domain, is missing or of another kind. Each line says where the name was set. | Add the action, or name one the resource has. |
No columns defined for the table. | The table has a route and no columns after discovery, with or without a columns block. | Add a column, or auto_columns do ... end. |
Column `x` is not a resource field. | The name is not an attribute, relationship, calculation or aggregate, and the column has no different source. | Add static true and requires if the column is computed. |
Static column `x` with render requires `requires` option. | A static column with a render function and no requires. | List the fields the render function reads. |
Static sortable column `x` must specify `sort_field`. | A column with static true and sortable true and no sort_field. | Add sort_field [:db_field]. |
Column `x` has invalid sort_field values: ... | sort_field names a field the resource does not have. | Use a real attribute or relationship. |
filters section requires at least one filter. | A filters block with nothing in it. | Add a filter, or remove the block. |
Filters depend on non-existent filters: ... | depends_on names a filter that is not declared. | Declare the parent filter. |
Relation filter :x uses :static mode but the target resource's action has required pagination | A static relation filter loads every option, and the target's read action requires pagination. | Set required?: false on the action, or use mode :search or :search_multi. |
A relation filter message about display_field and search_field | display_field is a function of one argument and there is no search_field. A function of two arguments falls back to searching :name. | Add search_field :name. |
Filter groups reference non-existent filters: ..., Filters assigned to multiple groups: ... | A group names a missing filter, or a filter is in two groups. | Fix the name, or keep the filter in one group. |
Action :x of type :link requires a :path option | A :link action without path. | Add path fn record -> "/admin/x/#{record.id}" end, or a fixed string. A string is used as written. |
Action :x of type :event requires an :event option | An :event action without event. | Add event "my_event". |
Dropdown :x requires a ui block with label, Dropdown :x requires a label in ui block | A dropdown without a ui block, or one without a label. | Add ui do label fn -> ... end end. |
bulk_actions section requires at least one action. | A bulk_actions block with no action, including a block that sets only enabled. | Add an action, or remove the block. |
archive section requires AshArchival.Resource extension | An archive block on a resource that does not use AshArchival.Resource. | Add the extension, or remove the block. |
AshArchival.Resource is in the resource extensions, but no archive configuration is defined. | The reverse: the extension without an archive block on the resource or its domain. | Add archive do ... end to the resource or the domain. |
realtime prefix is required when enabled. | A realtime block without prefix. | Add prefix "posts", or enabled false. |
UI adapter module ... is not loaded, PubSub module ... is not loaded | A domain default names a module that does not exist. | Check the module name and the dependency. |
Pagination messages about page_size, page_size_options, max_page_size or type | page_size must be a positive integer, and a member of page_size_options when both are set. page_size_options cannot be an empty list, and each option must be a positive integer. max_page_size must be at least the largest option. type must be one of the three. The check is skipped with enabled false. | Fix the value. |
Duplicate notice names: ..., Notice `x`: ..., Notice `x` position ... references unknown column ... | Two notices share a name, a position is not valid, or a column position names an undeclared column. | Copy the position from Table layout and presentation DSL. |
Form compile messages
| Message | Cause | Fix |
|---|---|---|
form identity.name is required | The form identity has no name. | Add identity do name :post_form end. |
Missing required form source action(s): ... | A form with any field needs create, update and read. | Declare all three on the resource or the domain. |
... form names actions the resource does not have: ... | A create, update or read action is missing or of another kind. | Add the action, name one the resource has, or close the mode with access :update, false. |
Field `x` is not a resource attribute. | The name is not an attribute, relationship, calculation or aggregate. | Add virtual true. |
Field `x` depends_on `y` which is not a defined field. | depends_on names a field that is not in the form. | Declare y in the same form. |
Virtual field `x` of type ... requires a `resource`, `options` or `options_source` option. | A virtual :relation or :select field with no source of choices. | Add resource or options. |
`nested_field` is only allowed inside fields with type `:nested`. | A nested_field in a field of another type. | Make the field :nested, or remove the entries. |
Group `x` references fields that don't exist: ... | A group names a missing field. | Fix the name, or declare the field. |
Group `x` contains fields already in another group: ... | A field is in two groups. | Keep it in one group. |
Layout mode `x` requires at least one step to be defined. | :wizard or :tabs without steps. | Add step :name do groups [...] end. |
Steps cannot be defined when layout mode is `:standard`. | Steps in a standard form. | Use mode :wizard or :tabs, or remove the steps. |
Wizard mode requires `:sequential` navigation. Use `:tabs` mode for free navigation. | navigation :free with :wizard. | Use mode :tabs. |
Step `x` references groups that don't exist: ..., Step `x` contains groups already in another step: ... | A step names a missing group, or a group is in two steps. | Name groups that exist, and keep each group in one step. A group that is in no step is allowed. |
At most one step can have `summary: true` ... | Two summary steps. | Keep one. |
Upload `x` references field `y` which doesn't exist. | The upload's field is not a field of the form. | Declare field :y, :upload. |
Upload `x` has invalid accept format ... | accept is not a valid string or list. | Use "image/*,.pdf" or ~w(.jpg .png). |
Upload `x` references external module ... which could not be loaded., and the same for writer | The module does not exist. | Check the module name. |
Duplicate notice names: ..., Notice `x` position ... references unknown group ..., Notice `x` only_steps references unknown steps: ... | A notice name, position, group or step is wrong. | Copy the position from Form groups and layout DSL. |
| A preload raises about pagination | A preloaded relationship's read action requires pagination. | Set pagination offset?: true, required?: false on that action. |
Run-time symptoms
| Symptom | Likely cause |
|---|---|
BadArityError in a predicate | The wrong arity. A row action visible takes fn record, state. A realtime visible takes fn record, user, and a menu group visible takes fn user. The global form gate access fn mode, state takes two arguments. Every other predicate takes fn state. |
Ash.Error.Invalid.LimitRequired | A preloaded relationship's read action requires pagination. |
Aggregate queries not supported | The data layer cannot count. A :numbered table always counts. For :load_more or :infinite, set ui do show_total false end in pagination. |
A render function gets a map, not a value | A static column with requires receives a map of those fields. Any other column receives the formatted value. |
A cell raises UndefinedFunctionError | The column ui block names a type atom with no renderer module, such as a misspelling, or :image, :avatar, :currency, :percentage, :time, :progress, :json or :custom. See Built-in types. |
A column shows %Ash.NotLoaded{} | The relationship is not in source.preload. |
| No rows after adding a route param | A path param whose name matches an attribute became a filter. |
| A bulk action flash never appears | The hook called Phoenix.LiveView.put_flash/3 inside the component. Use BulkActionHooks.put_flash/3 and add the {:put_flash, kind, message} clause to the parent. |
| The table never refreshes | The parent does not forward :gervaz_refresh. |
| Realtime updates never arrive | The parent does not forward the %Phoenix.Socket.Broadcast{}, realtime.prefix does not match the topic of the resource's pub_sub, or no pubsub module is configured. The table subscribes only when enabled, pubsub and prefix are all set. |
| URL filters are ignored | handle_params does not call UrlSync.decode/3, or url_state is not passed to the component. |
| Load more loses earlier pages in a custom template | The template groups rows and needs keep_loaded_records true. |
| The form renders no fields | source.access denies the mode. |
| A modal closes twice, or flickers | Both the js hooks and the parent's {:form_saved, ...} handler close it. Use one. |
| A hidden field's value is missing on save | hidden_fields without a matching defaults entry. |
| A JS hook does nothing | The root element lost id={"#{@static.id}-form-wrapper"}, or the page has no gervaz:exec-js listener. |
| The DSL reformats with parentheses | :mishka_gervaz is missing from import_deps, or Spark.Formatter is missing from plugins. |
| A domain default is ignored | That key is not inherited. See How domain defaults work. |
Options that are accepted but not read
These options pass the schema and land in the compiled config, but no built-in template, handler or loader reads them. Setting one changes nothing today. A custom template can read any of them from the config. Each row names what to use instead.
| Where | Option | Use instead |
|---|---|---|
| Table and form source, and the domain | actor_key | Pass the user as the current_user assign of the component. |
| Table and form source, and the domain | master_check | Override master_user?/1 in a custom access module. The built-in one treats a user whose site_id is nil as a master, and a map without the site_id key is not a master. |
| Table column | searchable | A :text filter with fields. |
| Table column | filterable | Declare the filter in filters. |
| Table column | export, export_as | Nothing. Gervaz has no built-in export. |
Table column ui | align, min_width, max_width | The width option and the class options. The built-in template reads width. |
Table auto_columns | The ui_defaults block | A ui block on each column, or in an override. |
| Table filter | presets | A :select filter with explicit options. |
| Table filter | virtual | It records intent only. resource and apply do the work. |
Table actions_layout | auto_collapse_after | List the actions you want drawn in inline and dropdown. |
| Table presentation | The responsive block | Nothing today. |
| Table presentation | theme.border_class, theme.extra | The header_class and row_class keys, which the plain table reads. |
| Table presentation | features values :export, :reorder, :inline_edit | Nothing. No built-in template draws them. |
| Table row | selectable | It makes get required. The checkboxes come from the :select feature and the bulk actions. |
| Form field | apply, format, render, options_source, array_fields | A before_save hook, a custom field type, or the UI adapter. |
Form auto_fields | ui_defaults keys number_step, select_prompt, datetime_format | The step, placeholder and similar options in each field's ui block. boolean_widget and textarea_threshold are read. |
| Form step | action, on_enter, before_leave, after_leave | Override can_advance?/2 in the step handler. |
| Form step | summary | Gervaz checks when it compiles that one step at most sets it. The built-in template draws that step like any other. |
| Form layout | responsive | CSS on the group or the field. |
| Form layout | persistence | Nothing. The step handler keeps step state in the form state only. |
| Form presentation | features | Remove the DSL that produces the feature. |
| Form presentation | The theme block: form_class, field_class, label_class, error_class, extra | The class options in field, group and submit ui blocks, or a UI adapter. |
| Form upload | show_preview, dropzone_text, ui.preview_class | A label in the upload's ui block, or the adapter's upload_dropzone/1 and upload_preview/1. |
| Form hooks | transform_params, transform_errors | A before_save hook, or override SubmitHandler.transform_params/2. |
| Form hooks | after_save, on_error as server hooks | The js hooks of the same names, or the parent's {:form_saved, ...} message. |
| Form field | min, max, preload, and ui keys step, class, wrapper_class | Nothing in the Standard form template. A custom template or adapter can read them. |
| Form step | visible, and ui keys icon, description, class, header_class | Nothing in the Standard form template. |
| Form group | collapsed, position, and ui keys icon, description, header_class, extra | Nothing in the Standard form template. |
| Form submit | position, and ui keys submit_class, cancel_class, wrapper_class, extra | Nothing in the Standard form template. |
Form upload ui | label, icon, class, extra | The adapter's upload_dropzone/1. |
| Table row | event, payload, and a row action of type :row_click | A row action of type :event. |
Table error_state | The whole section | Nothing. The built-in templates do not draw it. |
Table actions_layout and dropdown | position, and dropdown ui keys label, class, extra | The dropdown button draws only its icon. |
| Table bulk actions | enabled, payload | Leave out the bulk_actions block to have none. |
Table row and bulk action ui | extra | Nothing in the built-in action types. |
Table column ui | label | The label option in the column body. |
| Table filter group | ui keys description, class, header_class, extra | The group's ui columns, label and icon. |
Table layout header, footer and notice | extra | Nothing in the built-in templates. |
| Table notice | The positions {:before_column, name} and {:after_column, name} | Another position. |
| Table presentation | filter_mode values :modal and :drawer | :inline or :sidebar. The other two draw a Filters button that opens nothing. |
| Table refresh | pause_on_interaction, show_indicator, pause_on_blur | Refresh.pause/1 and resume/2 in your own code. |
Table pagination ui | first_label, last_label | Nothing. The pager has no First or Last button. |
| Domain | Pagination enabled, the pagination ui block, and archive enabled | Set pagination labels on the resource. For archive, use enabled false on the resource's own archive block. The domain does not pass these on. |
| Table and domain archive | visible as a function | A boolean. Gervaz evaluates only a boolean and shows the toggle otherwise. |
| Behaviour callbacks | FilterType.label/1, ColumnType.cell_class/1, FieldType.default_ui/0 | Nothing. Gervaz does not call them. |
This list comes from searching the code that runs at run time for each option. An option can still reach a custom template through the config.