Hi Martin,

My bad, as always I should have made a small unit test before concluding
something.

My detach-cascade assumption was incorrect, with regard to ListView.

Wicket’s ListItemModel does not, in fact, do a detach cascade.
So while it *is* getting detached mid-render, that does not lead to any
issues with the ListView model…

Oh well, back to the drawing board to figure out what is happening here in
our app; These “once every 6 months” bugs are something else.
The observed behavior when the bug occurs *should not be possible* stepping
through the code.
But of course those are the bugs that are most satisfying to fix 🙂

Met vriendelijke groet,
Kind regards,

Bas Gooren


Op 27 feb 2026, 09:18:52 schreef Martin Terra via users <
[email protected]>:

> Can you post a quickstart that reproduces the issue?
>
> to 26.2.2026 klo 17.43 Bas Gooren via users ([email protected])
> kirjoitti:
>
> Hi all,
>
>
> I have an interesting case, which I will admit I lost some sleep over 😉
>
>
> The ListView API is not stable WRT its model.
>
>
> We have not been able to reproduce this, but this is what we get in
>
> production:
>
>
> Caused by: java.lang.NullPointerException: Cannot invoke
>
> "java.util.List.get(int)" because the return value of
>
> "org.apache.wicket.markup.html.list.ListView.getModelObject()" is null
>
> at
>
>
>
> org.apache.wicket.markup.html.list.ListItemModel.getObject(ListItemModel.java:55)
>
> ~[wicket-core-9.19.0.jar:9.19.0]
>
> at ....SectionsPanel.createSection(SectionsPanel.java:57) ~[-]
>
> at ....SectionsPanel$1.populateItem(SectionsPanel.java:48) ~[-]
>
> at
>
> org.apache.wicket.markup.html.list.ListView.onPopulate(ListView.java:523)
>
> ~[wicket-core-9.19.0.jar:9.19.0]
>
> at
>
>
>
> org.apache.wicket.markup.repeater.AbstractRepeater.onBeforeRender(AbstractRepeater.java:124)
>
> ~[wicket-core-9.19.0.jar:9.19.0]
>
> at org.apache.wicket.Component.beforeRender(Component.java:949)
>
> ~[wicket-core-9.19.0.jar:9.19.0]
>
> at
>
>
>
> org.apache.wicket.MarkupContainer.onBeforeRenderChildren(MarkupContainer.java:1759)
>
> ~[wicket-core-9.19.0.jar:9.19.0]
>
>
> The simplest way to explain this:
>
>
> We have a ListView in a stateless page.
>
> The ListView gets a list model mapped from an LDM on the page:
>
>
> var parentModel = LoadableDetachableModel.of(() ->
>
> fetchItemFromCacheAndExternalApi());
>
> … = new ListView(“id”, parentModel.map(Parent::getItems)) { … }
>
>
> For a reason unknown at this time, which only happens under high load, this
>
> stateless page is re-rendered.
>
>
> On the re-render of the ListView, it walks through its onPopulate method.
>
>
> First it calls getViewSize() to check if there are items to render (parent
>
> model is non-null and says: here’s a list of X items)
>
> Reuse items is off, so it calls removeAll => all children are removed and
>
> detached => which also detaches the list model and the page model
>
> It then assumes the “size” is still correct and starts creating and
>
> appending children (ListItem instances).
>
> Once those populate and call their ListItemModel.getObject(), the parent
>
> model reattaches and now returns null => Boom, there’s the NPE.
>
>
> The reason that our page model returns non-null and null in quick
>
> succession is spam bots and thus cache issues; An external API we load data
>
> from also seems to misbehave and sometimes return empty results under load.
>
> This particular issue caught me by suprise, as normally a LDM is only
>
> loaded once during render cycle; Here it loads *twice*: for getViewSize()
>
> and then for the first ListItemModel, because it got detached by
>
> ListView#removeAll.
>
>
> But more to the point: the ListView proceeds, after calling removeAll(), as
>
> if nothing can have changed. And that is not correct, the ListView model
>
> may have been detached by removing children and thus have a different value
>
> now.
>
>
> Should ListView not re-calculate/query getViewSize() after calling
>
> removeAll()? That would remove this edge case?
>
>
> Met vriendelijke groet,
>
> Kind regards,
>
>
> Bas Gooren
>
>
>

Reply via email to