Error 414 when posting/updating via API

Hello everybody!
When trying to post or update a message whose content exceeds a certain size (the exact size I cannot detemine yet - is there a way to check this?) NGINX refuses to accept the POST or PUT requests and returns Error 414.
Is there a way to change (permanently) the default configuration delivered with the Discourse image, so that a larger payload size (at least matching the default 32000 characters in the admin settings) is accepted via API?

Have you checked the settings for “max post size”? There is also discussion here about increasing it.

If your posts via the API are getting cut off smaller than that, I’d be surprised.

Yep, I did. It’s currently set to the default value of 32000 characters and I’m trying to push via API a payload of about 6000 characters. I think that the error comes from NGINX and not from Discourse…

1 Like

After a bit of searching online I found that the problem might be related to the size of URL of the PUT request performed when I update a post via API.
This is actually rendering ineffective the setting “max post length” in Discourse admin, currently at the default value of 32000 characters.
Would it be possible to change the nginx template matching the web server configuration with the default Discourse configuration?


You can change nginx settings in the yml file. You can look in the discourse_docker/templates directory for some examples.

I usually edit them in the container to debug and then apply those settings to new containers in app.yml.

3 Likes

Just to document what I did for future visitors, I have manually added the options suggested in the topics linked in my previous message.

client_header_buffer_size 64k;
large_client_header_buffers 4 64k;

The values might be different for other users, but they look more than enough for my needs.

These options shall be manually added to the /etc/nginx/conf.d/discourse.conf NGINX configuration file, and after having restarted nginx service in the container, the problem will be solved.

Obviously this has to be redone manually at every container rebuild, unless this setting is added to the official web templates.

1 Like

One last post - the error was caused by me, hence no change to the templates is needed, at all! :expressionless:

I’m placing my API requests using the requests python library, and I was submitting the payload using parameter params=payload rather than data=payload, hence my oversized payload was handled in the “wrong” way.

I changed my call from this

r = requests.put(apiWebsite + '/posts/' + str(apiPost), params=payload)

to this

r = requests.put(apiWebsite + '/posts/' + str(apiPost), data=payload)

Sorry! :blush:

8 Likes

[quote=“marcozambi, post:7, topic:98186, full:false”][/quote]
We are having a similar problem when creating a post using the POST method.
And when the post is long the 414 error arrises.

We are using the discourse api in python to generate some post using the discourse api.

The create_post function seems to us a POST request using params instead of data.
This is the create_post definition form the discourse api

def create_topic(self, title, raw, category=None, created_at=None):
        response = self._request('POST', 'posts.json', params={
            'title': title,
            'raw': raw,
            'category': category,
            'created_at': created_at,
        })

We have tried to change params by data in the function definition.

We have tried using PUT instead of POST.
But it does not work.

The problem seem to be that the complete post is passed as parameters in the URL instead of an internal payload.

Is this a bug?
How may we create a long post using data payload instead of URL parameters?

Hmmm, it’s not very clear to me what kind of module you’re using to submit your POST request. I use requests and I prepare a post request like I show you here below.

The POST method is to create new posts; PUT is to modify existing posts.
Please check the API documentation here: https://docs.discourse.org/

import requests, json

headers = {
    'Content-Type': 'application/json',
    'Api-key': envDiscourseKey, # API key passed in this variable
    'Api-username': envDiscourseUsername # API user passed in this variable
}

tags = ['first-tag','second-tag']

payload = {
	'title': 'Sample title',
	'category': 123,
	'tags': tags,
	'raw': 'Raw text of your post'
}

r = requests.post('https://www.yourwebsite.xyz/posts', headers=headers, data=json.dumps(payload))
returnedData = r.json()
status = r.status_code

Also, as I explained here passing the payload through the params parameter was a mistake on my part and shall not be done.
I hope this helps

2 Likes

Thanks a lot for your quick response.

We are using a python warpper to the oficial JavaScript api from discourse:
https://github.com/samamorgan/discourse

It seems a wrapper to the official discourse one.

The problem is that in the definitions it uses params= (as you can see in the extracted function definition from the clients.py file).
It passes the title and raw data in params.

We have changed the definition of the creata_post function to data=
but then it does not work.

I see. Well, it seems that the problem lies in the wrapper implementation.
You don’t need any wrapper, in my opinion. Apart from the requests and json modules, the code I posted is just plain python3.
Try to go with that, maybe defining your own wrapper functions.

2 Likes

I see, you are right.

The problem is that we are not very proficient in python.

But it seems the wrapper implementation is not good.

But even if we have changed params to data in the function definition it does not work

We will try to use this code to create the post instead of the wraper code.

I am not the one who is doing the program, I program in JavaScript and other languages but not python.

I will try to explain the programmer how to do this (he is a bit confused he was using the wrapper thinking it was the official discourse api implementation, and the wrapper uses post as the name of the method to create the post, while the underlying python llibrary request uses post as the name of the method to sen a POST message, I think that is what he is not understanding well).

2 Likes

We have tried your code, but we receive a 403 error as response.

It seems that there is some kind of authoritation problem.
But we are using the same api key and user that we used previously (with the api wrapper) and it worked…
do you have any idea?

I will tel the programmer to check in and explain it better.

They are trying to use python though, not curl.

The example they mention above has the correct headers.

2 Likes

Hi Marco,

I’m Fernando’s colleague. I’ve implemented your code and it works fine and problem is solved.

Thanks a lot!
Albert.

2 Likes

Thank you all specially to marco who provided the python code.

Now it works.
we made and error and use api-key instead of Api-key.

we changed that and the code works.

I don’t know what is wrong in the wrapper that we were using (besides using params= instead of url).
We changed params by data and it did not work, but the code seem to do exactly what Marco says (but using params which is not a the correcto way).

Thank you again

3 Likes

It’s not case sensitive on our side, is it @blake?

I am not the programmer, I don’t know python, just helped him to fix the error.

May be python is case sensitive or rhere is an option to activate it?

The program worked just changing that.

Nope. Rails/Rack converts all headers to UPPER CASE for us. There is nothing in our code that is checking for case sensitivity.

Rails now attaches HTTP_ to the header as well as converting it to all caps so it would now be: request.headers[“HTTP_CONTENT_TYPE”]

3 Likes