Behaviour of API /v4/admin/ci/variables
Hello maintainers,
Please find the user story below for improvement / correction.
Scenario
Admin call the API https://docs.gitlab.com/api/instance_level_ci_variables/ call to create or update Instance level variables. The variables may or may not exist.
Return code 409 on already existing variable (POST)
Current behaviour
The API return a 400 error.
{"cache_control": "no-cache", "changed": false, "connection": "close", "content": "{\"message\":{\"key\":[\"(CI_TEMPLATE_REGISTRY_HOST) has already been taken\"]}}", "content_length": "74", "content_type": "application/json", "date": "Thu, 17 Jul 2025 10:23:53 GMT", "elapsed": 0, "json": {"message": {"key": ["(CI_TEMPLATE_REGISTRY_HOST) has already been taken"]}}, "msg": "Status code was 400 and not [201, 409]: HTTP Error 400: Bad Request", "nel": "{\"max_age\": 0}", "redirected": false, "server": "nginx", "status": 400, "strict_transport_security": "max-age=63072000", "url": "https://gitlab/api/v4/admin/ci/variables", "vary": "Origin", "x_content_type_options": "nosniff", "x_frame_options": "SAMEORIGIN", "x_gitlab_meta": "{\"correlation_id\":\"01K0BYJY0WCSXTBQK2YE3CA941\",\"version\":\"1\"}", "x_request_id": "01K0BYJY0WCSXTBQK2YE3CA941", "x_runtime": "0.072870"}
The API should return a 409 conflict instead of a 400 as it's already the case for other endpoint and specified in the doc: https://docs.gitlab.com/api/rest/troubleshooting/
Allow PUT to create variable
As specified in the conventions, ex: https://datatracker.ietf.org/doc/html/rfc7231#section-4.3.4 https://restfulapi.net/rest-put-vs-post/
A request PUT should be able to create a variable, currently it return a 404:
curl --location --request PUT 'https://gitlab/api/v4/admin/ci/variables' --header 'Authorization
: Bearer glpat-to0ken' --form 'value=test' --form 'key=CI_TEMPLATE_REGISTRY_HOST1'
{"error":"404 Not Found"}%
While the post works:
curl --location --request POST 'https://gitlab/api/v4/admin/ci/variables' --header 'Authorization: Bearer glpat-to0ken' --form 'value=test' --form 'key=CI_TEMPLATE_REGISTRY_HOST1'
{"variable_type":"env_var","key":"CI_TEMPLATE_REGISTRY_HOST1","value":"test","protected":false,"masked":false,"raw":false,"description":null}%
PUT Json behaviour
The PUT does not seems functionnal with JSON data:
curl --header "Content-Type: application/json" --location --request POST 'https://gitlab/api/v4/admin/ci/variables' --header 'Authorization: Bearer glpat-to0ken' -d '{ "key": "CI_TEMPLATE_REGISTRY_HOST1", "value": "test" }'
{"variable_type":"env_var","key":"CI_TEMPLATE_REGISTRY_HOST1","value":"test","protected":false,"masked":false,"raw":false,"description":null}%
curl --header "Content-Type: application/json" --location --request PUT 'https://gitlab/api/v4/admin/ci/variables' --header 'Authorization: Bearer glpat-to0ken' -d '{ "key": "CI_TEMPLATE_REGISTRY_HOST1", "value": "testtoto" }'
{"error":"404 Not Found"}%
While it works if you send it with the path in URL:
curl --header "Content-Type: application/json" --location --request PUT 'https://gitlab/api/v4/admin/ci/variables/CI_TEMPLATE_REGISTRY_HOST1' --header 'Authorization: Bearer glpat-to0ken' -d '{ "key": "CI_TEMPLATE_REGISTRY_HOST1", "value": "testtoto" }'
{"variable_type":"env_var","key":"CI_TEMPLATE_REGISTRY_HOST1","value":"testtoto","protected":false,"masked":false,"raw":false,"description":null}%
Have a good day / great weekend.