Here is my test code: public class HomePage extends WebPage {
private static final long serialVersionUID = 1L; private String word; public HomePage(final PageParameters parameters) { add(new FeedbackPanel("feedback") { private static final long serialVersionUID = 1L; @Override protected void onBeforeRender() { System.out.println("= = = = FeedbackPanel onBeforeRender()"); System.out.println(" FeedbackbackMessageModel = " + getFeedbackMessagesModel().getObject()); super.onBeforeRender(); } }.setOutputMarkupPlaceholderTag(true)); // if the word "blowup" is entered, //this register a error message and throw new AbstractRestartResponseException() IModel model = new Model() { private static final long serialVersionUID = 1L; @Override public Object getObject() { if (word != null && word.equals("blowup")) { word = "-w-e-b-l-e-w-u-p-"; HomePage.this.fatal("[2/2]This message is from Model."); // why this is NOT render in Ajax? getPage().detach(); System.out.println("! ! ! ! ! throwing new AbstractRestartResponseException()"); throw new AbstractRestartResponseException() { private static final long serialVersionUID = 1L; }; } else { return "The word is: \"" + (word == null ? " n u l l " : word) + "\""; } } }; add(new Label("message", model) { private static final long serialVersionUID = 1L; @Override protected void onBeforeRender() { System.out.println("= = = = Label onBeforeRender(), model = " + getModel().getObject()); super.onBeforeRender(); } }.setOutputMarkupId(true)); Form form = new Form("form", new CompoundPropertyModel(this)); add(form); form.add(new TextField("word").setRequired(true)); AjaxFallbackButton submitButton = new AjaxFallbackButton("submitButton", form) { private static final long serialVersionUID = 1L; @Override protected void onSubmit(AjaxRequestTarget target, Form f) { if (word != null && word.equals("blowup")) { HomePage.this.error("[1/2]This message is from onSubmit. There should also be a message from model"); } if (target != null) { target.addComponent(HomePage.this.get("feedback")); // clear error feedback if any target.addComponent(HomePage.this.get("message")); } } @Override protected void onError(AjaxRequestTarget target, Form f) { target.addComponent(HomePage.this.get("feedback")); // show updated error feedback } }; form.add(submitButton); } } Things work perfectly in non-Ajax. But in Ajax, after 'throw new AbstractRestartResponseException()' in model, the Ajax response to the browser is wrong in two places. 1) the feedback component don't have the second message register in the model, only the message from onSubmit(target) show. 2) the Ajax response is missing the second half: no Label component and the </ajax-response> end tag. ===== This is the normal Ajax response copy from the debug panel: INFO: Received ajax response (257 characters) INFO: <?xml version="1.0" encoding="UTF-8"?><ajax-response><component id="feedback4" ><![CDATA[<span id="feedback4"> </span>]]></component><component id="message1" ><![CDATA[<span id="message1">The word is: "bla"</span>]]></component></ajax-response> INFO: Response parsed. Now invoking steps... INFO: Response processed successfully. ===== This is the Ajax response after 'throw new AbstractRestartResponseException()': INFO: Received ajax response (339 characters) INFO: <?xml version="1.0" encoding="UTF-8"?><ajax-response><component id="feedback4" encoding="wicket1" ><![CDATA[<span id="feedback4"> <ul> <li class="feedbackPanelERROR"> <span class="feedbackPanelERROR">[1/2]^This message is from onSubmit. There should also be a message from model</span> </li> </ul> </span>]]></component> ERROR: Error while parsing response: Could not find root <ajax-response> element INFO: Invoking post-call handler(s)... INFO: Invoking failure handler(s)... >From tracing the wicket code, I just don't see how this can be. I see AjaxResponseTarget#response() is called again, and response.write("</ajax-response>"); is called on line 539. But in the end the Ajax response is wrong. What is wrong? Is this a bug? Here is the WicketApplication for the non-Ajax case: public class WicketApplication extends WebApplication { public WicketApplication() { } public Class<? extends WebPage> getHomePage() { return HomePage.class; } @Override public RequestCycle newRequestCycle(Request request, Response response) { return new WebRequestCycle(this, (WebRequest) request, (WebResponse) response) { @Override public Page onRuntimeException(Page page, RuntimeException e) { // page can be null if (page == null) { return super.onRuntimeException(page, e); } return page; } }; } }