<div dir="ltr">Thanks Markus for raising this and the feedback, and Pat for the proposal.<br><br>I'm hoping that my feedback on that point does not give the impression that I'm asking clients to cope with more variation so servers don't have to do the work, because that's not my intention. I do want to make sure we are not adding any unnecessary burden on the clients.<br><br>Another way to frame this, based on what I'm hearing and the potential objections to adding JSON as a third possible format, is to make a distinction between what the spec specifies and what it tolerates.<br><br>What the spec specifies is what clients can reliably parse in a structured way. Pat's plain text proposal (`{vocab term}: {human-readable explanation}`) seems like a another reasonable format/structure to use here. Clients that want to extract and display the error string have something defined to work with and VOTable remains valid for services that prefer it.<br><br>What the spec tolerates is a separate question: what a service can return while remaining compatible, with the understanding that it may not provide the optimal user experience.<br><br>A FastAPI service that emits a 422 with `{"detail": [...]}` shouldn't be treated as broken. It's just not returning an error in a structured way that clients can parse a message from. The body is advisory text. Clients can display whatever they get (show the JSON as-is, or even ignore the body and show something based on the status code). Only the HTTP status code triggers any  branching logic. JSON in this framing isn't a third parsing path and displaying the raw body is valid client behaviour.<br><br>The language that might capture this: the body MAY be any human-readable format where producing the specified format would require unreasonable effort from the framework or infrastructure. <div>That would cover FastAPI 422s, Pydantic validation errors and anything else the framework generates before application code runs, without endorsing any specific JSON schema as something clients need to parse.<br><br>The machine-readable signal is the status code and that's what's authoritative (400 means bad parameters, 422 means invalid values, 503 try again later) <br>The body is context for a human and I would say mandating a specific format for it is only justified if some client behaviour depends on parsing it, and to my understanding clients just display it. (Though client writers can chime in and disagree if this is incorrect)<br>The tradeoff is a potentially degraded user experience on services that don't implement the structured path, versus guaranteed structured errors at the cost of extra implementation work on every service using a modern framework. Also, I'm assuming that most clients already have to handle error formats outside of VOTable and plain text, since network-layer failures produce whatever the infrastructure gives them regardless of what the spec says, so that resilience is already expected of them.<br><br>To give a reference point from the implementation side, in our SIA service producing VOTable errors came out to around 200 lines across the exception handler and template:<br><br><a href="https://github.com/lsst-sqre/sia/blob/main/src/sia/templates/votable_error.xml">https://github.com/lsst-sqre/sia/blob/main/src/sia/templates/votable_error.xml</a><br><a href="https://github.com/lsst-sqre/sia/blob/main/src/sia/errors.py#L25">https://github.com/lsst-sqre/sia/blob/main/src/sia/errors.py#L25</a><br><a href="https://github.com/lsst-sqre/sia/blob/main/src/sia/main.py#L88">https://github.com/lsst-sqre/sia/blob/main/src/sia/main.py#L88</a><br><br>None of it is hard to write, but it's code every service author has to produce independently, has to test, and can go wrong in ways that are at times hard to catch. <br>It's a small but real burden on every new implementation, and I'm not convinced the tradeoff is worth it when the end result for the user is a string on screen either way, and the status code is what clients should be branching on.</div><div><br></div><div>Stelios Voutsinas</div></div><br><div class="gmail_quote gmail_quote_container"><div dir="ltr" class="gmail_attr">On Thu, Jun 18, 2026 at 6:01 AM Markus Demleitner via dal <<a href="mailto:dal@ivoa.net">dal@ivoa.net</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Dear DAL folks,<br>
<br>
two weeks ago I advertised the SCS2 working draft<br>
<<a href="http://mail.ivoa.net/pipermail/dal/2026-June/008878.html" rel="noreferrer" target="_blank">http://mail.ivoa.net/pipermail/dal/2026-June/008878.html</a>>; interest<br>
at least week's interop was good, so I think we ought to go ahead.<br>
<br>
As promised two weeks ago, I'd like to bring up points from Stelios'<br>
feedback<br>
<<a href="https://github.com/msdemlei/scs2-original-deleteme/issues/2" rel="noreferrer" target="_blank">https://github.com/msdemlei/scs2-original-deleteme/issues/2</a>> [1]<br>
in suitable packages, and I'll start with one we've discussed a bit<br>
at the Interop already:<br>
<br>
<br>
> The spec is clear on this "all responses, including errors, must be<br>
> in VOTable unless the client has requested a different<br>
> RESPONSEFORMAT."<br>
><br>
> While I do see the benefits, and it does give clients a single<br>
> parsing path for both successful and error responses, this<br>
> requirement makes writing services with modern HTTP frameworks<br>
> awkward.<br>
> FastAPI for example, automatically generates JSON validation errors<br>
> with HTTP 422 responses.<br>
><br>
> Overriding this to produce VOTable requires custom exception<br>
> handlers for every error path and I would argue is a hurdle that<br>
> goes against the "implementable within a week" target because you<br>
> end up fighting against the frameworks and their own validation<br>
> mechanisms.<br>
><br>
> Also, since we define any client behavior that requires parsing<br>
> error bodies in a structured way, I don't really see a huge win for<br>
> clients being able to parse the error body, versus just showing it<br>
> as it is came in the user.<br>
><br>
> I'd argue that the HTTP status codes are more important for the<br>
> client and already carry the machine-readable signal (400 = bad<br>
> parameters, 422 = invalid values). They can then choose to either<br>
> display information just based on the status code, include the<br>
> extra context either by default or as a "Extra information on the<br>
> error" button, and then potentially even parse the response if it<br>
> comes in a format they can deal with. (Existing clients who know<br>
> VOTable parse and return the relevant text, if they get JSON they<br>
> can either parse it or just show it as JSON)<br>
><br>
> I see the error body is advisory context and I think the format is<br>
> a convenience choice, and by forcing it to be VOTable creates an<br>
> implementation burden for service authors using modern HTTP<br>
> frameworks.<br>
><br>
> My take is that the requirement to produce VOTable errors should<br>
> either be relaxed to allow any human-readable format for 4xx<br>
> responses, or the spec should define the IVOA should define use<br>
> cases that make VOTable parsing of error bodies necessary.<br>
<br>
First off: What SCS2 right now says is basically what DALI has, and I<br>
think whatever we decide here should be fed back to DALI.<br>
<br>
Then, my minimal requirement is that *if VO code comes into play at<br>
all*, clients should ideally have one clear way to get a string to<br>
display to the user when something goes wrong.  Perhaps I can live<br>
with two ways, but when clients have to expect three different<br>
formats in which services report errors, I'd raise a veto.<br>
<br>
This clearly is different when the VO code doesn't even get to<br>
respond; of course there are network timeouts, 504 from reverse<br>
proxies and a bunch of other nastyness that may very well lead to<br>
ugly, ununderstandable diagnostics.  But that we can't help as long<br>
as we operate over a network, so let's concentrate on what we can<br>
help.<br>
<br>
Meanwhile, Joshua has posted the sort of code they need to turn<br>
messages from their framework into VOTables at<br>
<<a href="https://github.com/msdemlei/scs2-original-deleteme/issues/2#issuecomment-4650305818" rel="noreferrer" target="_blank">https://github.com/msdemlei/scs2-original-deleteme/issues/2#issuecomment-4650305818</a>>.<br>
<br>
My thoughts on this are: This is not insane code by any measure.  On<br>
the other hand, if we allow multiple sorts of error responses, this<br>
kind of work will need to be done in each client.  I feel pushing<br>
responsibility there would be a bad move because:<br>
<br>
(1) Clients are a scarce resource; let's make it easier for them<br>
<br>
(2) The error parsing paths on the client side generally are much<br>
less well-tested than the good path, and hence it's much more likely<br>
that this stuff will be broken.  Getting wild errors and tracebacks<br>
when, really, something else is wrong is the sort of user experience<br>
that makes people hate the world.<br>
<br>
(3) If it's done on the server side, validators can much more easily<br>
catch gross errors.<br>
<br>
But that's not *much* more than my 2 cents.  I would, for instance,<br>
be open to Datalink-style error messages (controlled vocabulary term:<br>
human-readable explanation) as well.  It's a bit ugly that<br>
QUERY_STATUS signalling then become asymmetric between good and<br>
failing requests, but then the VOTable wrapping of diagnostics isn't<br>
too pretty either.<br>
<br>
Other thoughts?<br>
<br>
Thanks,<br>
<br>
          Markus<br>
<br>
[1] If anyone can move this bug to the new SCS2 repo, please do so;<br>
it seems I can't.<br>
<br>
</blockquote></div>