<p>I want to patch an existing secret resource within Kubernetes. The object is called <code>centos-secretstorage</code> within the <code>default</code> namespace. I want to add a simple label of <code>test: empty</code>. However, this fails when the secret object <code>centos-secretstorage</code> exists, but it doesn't have any existing labels. If I manually label the secret with something else beforehand via <code>kubectl label centos-secretstorage hello=world</code>, and rerun my golang code. It is able to add the <code>test: empty</code> label successfully.</p>
<p>However, I want to have this be able to add a label regardless if existing labels exist or not.</p>
<pre><code>type secret struct {
    namespace string
    name      string
}

func main() {
    k8sClient := k8CientInit()

    vaultSecret := secret{
        namespace: &quot;default&quot;,
        name:      &quot;centos-secretstorage&quot;,
    }

    vaultSecret.patchSecret(k8sClient)
}

type patchStringValue struct {
    Op    string `json:&quot;op&quot;`
    Path  string `json:&quot;path&quot;`
    Value string `json:&quot;value&quot;`
}

func (p *secret) patchSecret(k8sClient *kubernetes.Clientset) {

    emptyPayload := []patchStringValue{{
        Op:    &quot;add&quot;,
        Path:  &quot;/metadata/labels/test&quot;,
        Value: &quot;empty&quot;,
    }}

    emptyPayloadBytes, _ := json.Marshal(emptyPayload)

    fmt.Println(string(emptyPayloadBytes))
    emptyres, emptyerr := k8sClient.CoreV1().Secrets(p.namespace).Patch(p.name, types.JSONPatchType, emptyPayloadBytes)

    if emptyerr != nil {
        log.Fatal(emptyerr.Error())
    }

    fmt.Println(emptyres.Labels)

}
</code></pre>
<p>Error: <code> the server rejected our request due to an error in our request</code></p>

<p>The problem is that the <code>add</code> operation in the JSON patch strategy requires the path to point to an existing map, while the object you are patching does not have this map at all. This is why when <em>any</em> label exists, the patch succeeds. We can work around this by using a different patch strategy. I think the <code>merge</code> strategy should work well.</p>
<p>I was able to reproduce this (on a namespace, but the object doesn't matter) using <code>kubectl</code> (which is generally useful when debugging the Kubernetes API):</p>
<ul>
<li><code>kubectl patch ns a --type='json' -p='[{&quot;op&quot;: &quot;merge&quot;, &quot;path&quot;: &quot;/metadata/labels/test&quot;, &quot;value&quot;:&quot;empty&quot;}]'</code> -&gt; fails</li>
<li><code>kubectl patch ns a --type='merge' -p='{&quot;metadata&quot;: {&quot;labels&quot;: {&quot;test&quot;: &quot;empty&quot;}}}'</code> -&gt; succeeds</li>
</ul>
<p>Using Golang client-go it would look something like this (didn't actually compile / run this):</p>
<pre><code>    payload := `{&quot;metadata&quot;: {&quot;labels&quot;: {&quot;test&quot;: &quot;empty&quot;}}}`
    emptyres, emptyerr := k8sClient.CoreV1().Secrets(p.namespace).Patch(p.name, types.MergePatchType, []byte(payload))
</code></pre>
<p>You can make the creation of the <code>payload</code> JSON nicer using structs, as you did with <code>patchStringValue</code>.</p>
<p>More info on patch strategies can be found here:</p>
<ul>
<li><a href="https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/" rel="nofollow noreferrer">https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/</a></li>
<li><a href="https://erosb.github.io/post/json-patch-vs-merge-patch/" rel="nofollow noreferrer">https://erosb.github.io/post/json-patch-vs-merge-patch/</a></li>
</ul>
