<p>I have a backend with golang that talks to k8s. I want to reformulate the error response that i get from k8s and send it to the frontend.</p>
<p>I want to return a meaningful validation error messages for the user, when he add a non valid name, something already exist ...</p>
<p>And i want something generic not hardcoded in each endpoint's controller.</p>
<p>I am using <code>kubernetes/client-go</code>.</p>
<ol>
<li><strong>First error</strong>:</li>
</ol>
<p>For example lets say i want to add a hotel to the <code>etcd</code>, when i try to add the hotel's name: hotel123,  that's already exist.</p>
<ul>
<li>I get this error message: <code>\&quot;hotel123\&quot; already exists</code>.</li>
<li>What i want : <code>hotel123 already exists</code>.</li>
</ul>
<ol start="2">
<li><strong>second error</strong>:</li>
</ol>
<p>For example lets say i want to add a hotel to the <code>etcd</code>, when i try to add the hotel name: hotel_123, that's alerady exist.</p>
<ul>
<li>I get this error message: <code>\&quot;hotel_123\&quot; is invalid, Invalid value: \&quot;hotel_123\&quot;...</code></li>
<li>What i want: <code>hotel_123 is invalid</code></li>
</ul>
<p>How to return a custom user friendly error message ?</p>
<p>PS: i have multiple functions, so the validation should be generic.</p>

<p>String <code>err.Error()</code> is the original, meaningful and best error message you can get from Kubernetes server for the user (Or you have to translate it by yourself).</p>
<p><strong>Explains:</strong></p>
<p>You need to look beyond the surface of <code>kubernetes/client-go</code> client library.</p>
<p>Each client talks to k8s server through <strong>HTTP REST APIs</strong>, which sends back response in <code>json</code>. It's the <code>client-go</code> library that decodes the response body and stores the result into object, if possible.</p>
<p>As for your case, let me give you some examples through the <code>Namespace</code> resource:</p>
<ol>
<li><strong>First error:</strong></li>
</ol>
<pre class="lang-json prettyprint-override"><code>POST https://xxx.xx.xx.xx:6443/api/v1/namespaces?fieldManager=kubectl-create
Response Status: 409 Conflict
{
  &quot;kind&quot;: &quot;Status&quot;,
  &quot;apiVersion&quot;: &quot;v1&quot;,
  &quot;metadata&quot;: {},
  &quot;status&quot;: &quot;Failure&quot;,
  &quot;message&quot;: &quot;namespaces \&quot;hotel123\&quot; already exists&quot;,
  &quot;reason&quot;: &quot;AlreadyExists&quot;,
  &quot;details&quot;: {
    &quot;name&quot;: &quot;hotel123&quot;,
    &quot;kind&quot;: &quot;namespaces&quot;
  },
  &quot;code&quot;: 409
}
</code></pre>
<ol start="2">
<li><strong>second error:</strong></li>
</ol>
<pre class="lang-json prettyprint-override"><code>POST https://xxx.xx.xx.xx:6443/api/v1/namespaces?fieldManager=kubectl-create
Response Status: 422 Unprocessable Entity
{
    &quot;kind&quot;: &quot;Status&quot;,
    &quot;apiVersion&quot;: &quot;v1&quot;,
    &quot;metadata&quot;: {},
    &quot;status&quot;: &quot;Failure&quot;,
    &quot;message&quot;: &quot;Namespace \&quot;hotel_123\&quot; is invalid: metadata.name: Invalid value: \&quot;hotel_123\&quot;: a lowercase RFC 1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name',  or '123-abc', regex used for validation is '[a-z0-9]\r\n([-a-z0-9]*[a-z0-9])?')&quot;,
    &quot;reason&quot;: &quot;Invalid&quot;,
    &quot;details&quot;: {
        &quot;name&quot;: &quot;hotel_123&quot;,
        &quot;kind&quot;: &quot;Namespace&quot;,
        &quot;causes&quot;: [
            {
                &quot;reason&quot;: &quot;FieldValueInvalid&quot;,
                &quot;message&quot;: &quot;Invalid value: \&quot;hotel_123\&quot;: a lowercase RFC 1123 label must consist of lower case alphanumeric characters or '-', and must start and end with an alphanumeric character (e.g. 'my-name',  or '123-abc', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?')&quot;,
                &quot;field&quot;: &quot;metadata.name&quot;
            }
        ]
    },
    &quot;code&quot;: 422
}
</code></pre>
<ol start="3">
<li><strong>normal return:</strong></li>
</ol>
<pre class="lang-json prettyprint-override"><code>POST https://xxx.xx.xx.xx:6443/api/v1/namespaces?fieldManager=kubectl-create
Response Status: 201 Created
{
    &quot;kind&quot;: &quot;Namespace&quot;,
    &quot;apiVersion&quot;: &quot;v1&quot;,
    &quot;metadata&quot;: {
        &quot;name&quot;: &quot;hotel12345&quot;,
        &quot;uid&quot;: &quot;7a301d8b-37cd-45a5-8345-82wsufy88223456&quot;,
        &quot;resourceVersion&quot;: &quot;12233445566&quot;,
        &quot;creationTimestamp&quot;: &quot;2023-04-03T15:35:59Z&quot;,
        &quot;managedFields&quot;: [
            {
                &quot;manager&quot;: &quot;kubectl-create&quot;,
                &quot;operation&quot;: &quot;Update&quot;,
                &quot;apiVersion&quot;: &quot;v1&quot;,
                &quot;time&quot;: &quot;2023-04-03T15:35:59Z&quot;,
                &quot;fieldsType&quot;: &quot;FieldsV1&quot;,
                &quot;fieldsV1&quot;: {
                    &quot;f:status&quot;: {
                        &quot;f:phase&quot;: {}
                    }
                }
            }
        ]
    },
    &quot;spec&quot;: {
        &quot;finalizers&quot;: [
            &quot;kubernetes&quot;
        ]
    },
    &quot;status&quot;: {
        &quot;phase&quot;: &quot;Active&quot;
    }
}
</code></pre>
<p>In a word, <strong>if the HTTP Status is not 2xx, the returned object is of type Status and has .Status != StatusSuccess, the additional information(<code>message</code> in this case) in Status will be used to enrich the error</strong>, just as the code snippets below:</p>
<pre class="lang-golang prettyprint-override"><code>createdNamespace, err := clientset.CoreV1().Namespaces().Create(context.TODO(), namespace, metav1.CreateOptions{})
if err != nil {
    // print &quot;namespaces \&quot;hotel123\&quot; already exists&quot; or so
    fmt.Println(err.Error())
    return err.Error()
}
fmt.Printf(&quot;Created Namespace %+v in the cluster\n&quot;, createdNamespace)
return &quot;&quot;
</code></pre>
