Troubleshooting#
Aggregated quick-reference for the errors that show up once and then never again — if you know what they mean. Grouped by where they surface.
Backend — schema / query errors#
<field> subtype not found in <Type>#
- Source:
DataFormatValidatorImpl.assignFormatType, thrown when a model field is typed as another model but no FK relationship exists from the owning table to the referenced one. - Root cause (99% of cases): The FK constraint is missing from the physical DB. Palmyra reads FKs from JDBC metadata and didn’t find one for this column.
- Fix: Add the
FOREIGN KEYconstraint in your schema migration; restart the app. If the FK must be app-managed (shared / read-only schema), declare it via@PalmyraMappingConfig. - Related: Schema Discovery explains the lookup path.
field limit not found for filter criteria#
- Source: Palmyra’s query-param parser seeing a reserved pagination key in the
filterslot. - Root cause: Client sent
limit=Nwhere a column name was expected — typically benign, library noise. - Fix: Ignore if it’s just noise. If your application logic relies on filters coming through, sanity-check the client code isn’t accidentally putting pagination controls into the filter map.
Mandatory attribute … must be provided on PUT#
- Source:
DataValidationExceptionduringUpdateHandlerinvocation. - Root cause: Palmyra’s update is a full-body replace, not PATCH. A partial request body missing a
mandatory = Mandatory.ALLfield 500s. - Fix: Either send the full object on update, or mark the field less strict (
Mandatory.CREATE— mandatory only on create).
Cannot compare left expression of type '<Entity>' with right expression of type 'Long'#
- Source: Spring Data JPA at bean creation, rejecting a repository method.
- Root cause: You changed a JPA entity field from
Longto@ManyToOne <Entity>. The existingfindByFoo(Long)method no longer matches — JPA seesentity.fooas an entity reference, not a scalar. - Fix: Rename to
findByFooId(Long)— Spring Data resolves"FooId"toentity.foo.id. - Related: JPA Coexistence.
500 instead of 401 on UnAuthorizedException#
- Source: Spring’s default exception handler sees an unhandled
UnAuthorizedExceptionfrompalmyra-dbpwd-mgmtand maps it to 500. - Fix: Add an
@RestControllerAdvicemapping → 401. Same forEndPointForbiddenException→ 403. See Security Configuration Recipes § 4.
IncorrectResultSizeDataAccessException in DevBootstrap#
- Source:
jdbcTemplate.queryForObject("SELECT id FROM …", …). - Root cause: Duplicate rows from an earlier buggy seed run.
queryForObjectexpects exactly one row. - Fix:
SELECT MIN(id) FROM …— tolerates duplicates, picks the earliest.
FK ALTER TABLE fails — “Cannot add or update a child row”#
- Source: Hibernate / DDL-auto or a manual
ALTERadding a FK constraint. - Root cause: Existing rows have FK column values that don’t match any row in the referenced table.
- Fix: Seed the referenced (lookup) table first, then install the FK. Clean up orphan rows if any pre-existing data is genuinely invalid.
Backend — runtime / config errors#
404 on every palmyra endpoint#
- Source: Spring’s DispatcherServlet.
- Root cause: Forgot
@Import(PalmyraSpringConfiguration.class)on your main class — no autoconfiguration metadata in the jar means the component scan never runs for Palmyra packages. - Fix: Add the import.
404 on GET /thing/{id}, works on GET /thing#
- Source: Handler that implements
ReadHandler(orUpdateHandler,DeleteHandler) without asecondaryMapping. - Fix: Add
secondaryMapping = "/thing/{id}"to the@CrudMapping.
500 + No FileUploadHandler registered for subType: X#
- Source:
tusmgmtextension’sFileUploadHandlerRegistry.resolve. - Root cause: No
@TusUpload("X")bean in the Spring context. - Fix: Add one, or correct the spelling mismatch vs the URL path variable. TUS Uploads integration guide.
406 on TUS PATCH#
- Source:
tus-java-serverContent-Type validator. - Root cause: Spring’s
CharacterEncodingFilterappended;charset=UTF-8toapplication/offset+octet-stream. - Fix:
server.servlet.encoding.enabled: falsein the test/prod profile — or in MockMvc tests,.characterEncoding((String) null).
Stale TUS uploads never clean up#
- Root cause:
@EnableSchedulingmissing on the main@SpringBootApplication. - Fix: Add it.
Frontend — build / runtime errors#
formatFooter is not a function in grid#
- Source:
ColumnConverter.jsinside@palmyralabs/rt-forms— expects theGridCustomizerto implement three methods. - Root cause: Hand-rolled
customizerwith onlyformatCell+formatHeader. - Fix: Use the
useGridColumnCustomizer(config)helper — it fills in all three automatically.
Grid shows [object Object] in FK columns#
- Source: Default cell renderer on a nested object.
- Root cause: Backend started returning nested objects (e.g.
patient = {id, externalCode, …}) but the grid column still treats the value as a scalar. - Fix: Wire a
cellRendereror auseGridColumnCustomizerenhancer that dot-walks —patient?.externalCode ?? patient?.id ?? ''. Always defensive against both scalar and object shapes.
403 on every mutating request from the SPA#
- Root cause: CSRF token not present / not echoed. Common causes:
- Missing
withCredentials: trueon axios → cookies don’t flow. CsrfTokenRequestHandlerstill deferred →XSRF-TOKENcookie never lands on the first GET.
- Missing
- Fix: Both sides. Backend:
CsrfTokenRequestAttributeHandlerwithsetCsrfRequestAttributeName(null). Frontend:ax.defaults.withCredentials = truein the store factory. See Session Auth wiring and Security Configuration Recipes § 3.
401 redirect loop on first page load#
- Root cause:
RequireAuthprobes/user/abouton mount, gets 401, redirects to/login,/loginrenders, user logs in — but something clears the session immediately. Usually a stale service worker or a misconfiguredwithCredentials. - Fix: Check that
withCredentials: trueis in the store factory’saxiosCustomizer, not just the login call. And verify the Vite proxy is configured — without it, cookies are cross-origin in dev.
DynamicMenu renders empty tree#
- Root causes (in order of likelihood):
- No seed data in
xpm_menu/xpm_acl_menu. - The logged-in user’s group has
xam.mask = 0everywhere. - Menu rows have
active = 0. - Wrong endpoint — must be
/acl/menu/listAll(not/acl/menu).
- No seed data in
- Related: Dynamic Navigation.
Clicking a DynamicMenu item navigates to a 404 route#
- Root cause:
xpm_menu.codedoesn’t match any React Router route. The defaultAsyncTreeMenuclick handler callsnavigate(row.code). - Fix: Either put the route path in
code(/patient, notPATIENT), or register alias routes inApp.tsxmatching the class-style codes.
Test profile gotchas#
MockMvc tests hang or fail randomly#
- Root cause:
ddl-auto: updateandtestcontainersdon’t mix well if the container is reused across test classes. - Fix:
ddl-auto: create-dropfor tests, or use@DirtiesContextto force per-test container cycling.
Basic auth works in CURL but not in MockMvc tests#
- Root cause: Missing
.with(csrf())on state-changing requests. - Fix: Either
.with(csrf())on each request, or disable CSRF in the test security config.
See also#
- Mental Model — has its own small error → fix table
- Schema Discovery — for all “field / relation doesn’t resolve” symptoms
- The integration guides — each extension’s integration-guide page has a Gotchas + Troubleshooting section scoped to that extension