I don't think it's actually possible to retrieve just the JSON string from inside a JSONException so in the end I took the answer from BNK and did what is probably the easiest solution in this situation.
The trick seems to be to receive a StringRequest and do the JSON processing once you know there's a valid string response. Here's how that looks in my project.
StringRequest request = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
@Override
public void onResponse(String response) {
activity.hideProgress();
try {
Object json = new JSONTokener(response).nextValue();
if (json instanceof JSONArray) {
// an array is a valid result
dataModel.loadData((JSONArray)json);
} else if (json instanceof JSONObject) {
// this is an error
showErrorMessageIfFound((JSONObject)json);
}
} catch (JSONException error) {
error.printStackTrace();
}
refreshTable();
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
activity.hideProgress();
showVolleyError(error);
// check for a JSONObject parse error
}
});
First there's a StringRequest to retrieve the response. The error response displays the error with my custom error processor. The success response parses the JSON and uses the end result to display the correct thing to the end user.