-
-
Notifications
You must be signed in to change notification settings - Fork 168
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Vague error message for 422 Unprocessable Content #885
Comments
Someone had a similar issue here: #856 (comment) Could you try to send the exact same request to the LinkAce demo? The API key is available in the user settings when logged in. Also, which version do you use? |
I see the same behavior on the demo. If Content-Length is missing, you get the "URL is required" error. Missing Content-LengthRequest:
Response:
Same exact request with Content-LengthRequest:
Response:
I saw this issue on 1.15.6 on my production instance. Looks like the demo is currently using 1.15.5. And before I upgraded to 1.15.6 yesterday, I was using and experiencing the same issue on 1.12.1. |
Could you try that again with the V2 demo? https://demo-v2.linkace.org/dashboard By the way: which tool do you use to make this request? |
curl -vvv --request POST \
--url http://my-local-linkace-2.app/api/v2/links \
--header 'Authorization: Bearer 1|VQw1dO9s....' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{
"url": "https://duckduckgo.com/updates"
}'
Note: Unnecessary use of -X or --request, POST is already inferred.
* Host my-local-linkace-2.app:80 was resolved.
* IPv6: (none)
* IPv4: 192.168.100.125
* Trying 192.168.100.125:80...
* Connected to my-local-linkace-2.app (192.168.100.125) port 80
> POST /api/v2/links HTTP/1.1
> Host: my-local-linkace-2.app
> User-Agent: curl/8.7.1
> Authorization: Bearer 1|VQw1dO9s....
> accept: application/json
> content-type: application/json
> Content-Length: 45
>
* upload completely sent off: 45 bytes
< HTTP/1.1 200 OK
< Date: Thu, 30 Jan 2025 12:38:06 GMT
< Server: Apache/2.4.58 (Ubuntu)
< Vary: Authorization
< Cache-Control: no-cache, private
< X-RateLimit-Limit: 60
< X-RateLimit-Remaining: 58
< Access-Control-Allow-Origin: *
< Transfer-Encoding: chunked
< Content-Type: application/json
<
* Connection #0 to host my-local-linkace-2.app left intact
{"url":"https:\/\/duckduckgo.com\/updates","title":"What\u2019s New in DuckDuckGo","description":"We\u2019re constantly making improvements to our product. Every quarter, we post the best of our most recent updates here.","user_id":2,"icon":"link","thumbnail":"https:\/\/duckduckgo.com\/static-assets\/image\/pages\/updates\/meta.png","updated_at":"2025-01-30T12:38:07.000000Z","created_at":"2025-01-30T12:38:07.000000Z","id":394,"tags":[],"lists":[]} however curl -vvv --request POST \
--url http://my-local-linkace-2.app/api/v2/links \
--header 'Authorization: Bearer 1|VQw1dO9s....' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--header "Content-Length:" \
--data '{
"url": "https://duckduckgogo.com"
}'
Note: Unnecessary use of -X or --request, POST is already inferred.
* Host my-local-linkace-2.app:80 was resolved.
* IPv6: (none)
* IPv4: 192.168.100.125
* Trying 192.168.100.125:80...
* Connected to my-local-linkace-2.app (192.168.100.125) port 80
> POST /api/v2/links HTTP/1.1
> Host: linkace-apache.pmx.local
> User-Agent: curl/8.7.1
> Authorization: Bearer 1|VQw1dO9s...
> accept: application/json
> content-type: application/json
>
* upload completely sent off: 39 bytes
< HTTP/1.1 422 Unprocessable Content
< Date: Thu, 30 Jan 2025 12:46:03 GMT
< Server: Apache/2.4.58 (Ubuntu)
< Vary: Authorization
< Cache-Control: no-cache, private
< X-RateLimit-Limit: 60
< X-RateLimit-Remaining: 58
< Access-Control-Allow-Origin: *
< Transfer-Encoding: chunked
< Content-Type: application/json
<
* Leftovers after chunking: 498 bytes
* Connection #0 to host linkace-apache.pmx.local left intact
{"message":"The url field is required.","errors":{"url":["The url field is required."]}} I think the behaviour is not entirely false in this context, as the error message is only sent as an addition to the actual issue: 422 Unprocessable Content The client doing the request should be able to correctly send those requests, and content-length is at least for HTTP1.1 a required header when sending data and the transfer is not chunked. Maybe there is a specific setting for the web server in front of LinkAce to handle this scenario, but I would not like to fix this edge case inside the application. |
I've been using Postman to test some of these requests. Behavior is identical on the v2 demo. I guess I got myself a bit confused yesterday focusing too much on the error message returned from LinkAce. I suppose I was expecting the message to explain the 422, which it technically doesn't, but I suppose is kind of technically correct as LinkAce must be trying to process an empty request or something. I've mentioned it before, but I'm working on a firefox extension to save pages to LinkAce. Found some time to work on it again lately, and I'm not noticing my requests weren't identical from the extension vs my testing with Postman. So, most of my trouble is stemming from not being a full-time JavaScript/TypeScript developer. I didn't realize the Fetch API doesn't automatically set the correct Content-Type headers, so the extension was sending Spent about 7 hours working on the extension yesterday and by the end of it my brain was apparently fried and I wasn't noticing all these details. I maintain the opinion that the server should explain why it was unprocessable, and give a more accurate response status in the case of an incorrect Content-Type. There's a reason standards exist. Worth noting there's also 411 Length Required, which should be returned if the server refuses to accept the request without a defined Content-Length, but most tools automatically calculate this, so this is a moot point. I don't know how much of this validation is configured in LinkAce vs being defined in the Framework. |
I will have a look if such cases can easily handled properly. |
I hope I'm not coming off unthankful or anything. I really do enjoy using LinkAce, I decided to stop using Pinboard and this is a fantastic replacement. Developing for the API has been a bit painful I have to admit. I whipped this up to see if it would help, and it kind of would, but this also feels completely incorrect now that I know those other HTTP statuses exist. Plus this would have to be duplicated on all endpoints, and that feels wrong, too! |
Hey, no worries. I am thankful for your input. 🙏 I have not yet worked with the LinkAce API beside doing some work via Zapier and with iOS shortcuts. |
I wonder if a Middleware would be a better place for it, and then it can apply to whatever routes it's configured for. I wonder if something like this would be a better route to go: class ValidateContentTypeHeader
{
public function handle($request, Closure $next)
{
if ($request->header("Content-Type") === "application/json") {
return $next($request);
}
return Response::json("Content-Type should be 'application/json'.", 415);
}
} I might keep playing around with this, too. |
I've been banging my head against the wall for the last few hours trying to figure this out:
I think I narrowed it down to a missing Content-Length header, but it would be really, really nice if the error returned from the server was accurate. Not every tool out there automatically calculates that header. (Looking at you, Fetch API.)
The text was updated successfully, but these errors were encountered: