<p>I have an instance of a Kubernetes <a href="https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/" rel="noreferrer">Custom Resource</a> that I want to patch via the Kubernetes API using a JSON patch.</p>

<p>This is my PATCH request:</p>

<pre><code>PATCH /apis/example.com/v1alpha1/namespaces/default/mycrd/test HTTP/1.1
Accept: application/json
Content-Type: application/json-patch+json
[other headers omitted for brevity...]

[
  {"op": "replace", "path": "/status/foo", value: "bar"}
]
</code></pre>

<p>I'm fairly certain that my request body is a valid <a href="http://jsonpatch.com/" rel="noreferrer">JSON patch</a>, and I've previously already successfully updated core (non-CRD) API resources using similar API calls. The CRD has a <code>openAPIV3Schema</code> defined that explicitly allows <code>.status.foo</code> to exist and to be of type <code>string</code>.</p>

<p>The request above is declined by the Kubernetes API server with the following response:</p>

<pre><code>HTTP/1.1 422 Unprocessable Entity
Conent-Type: application/json
[other headers omitted for brevity...]

{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {},
  "status": "Failure",
  "message": "the server rejected our request due to an error in our request",
  "reason": "Invalid",
  "details": {},
  "code": 422
}
</code></pre>

<p>According to the <a href="https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/#common-features" rel="noreferrer">CRD documentation</a>, CRDs should support <code>PATCH</code> request with the <code>application/json-patch+json</code> content type. But for some reason, the request appears to be invalid without Kubernetes bothering to tell me <em>why</em>. The API server pod did not have any relevant messages in its log stream, either.</p>

<p>The same error also occurs when using <code>kubectl patch</code> on the command line:</p>

<pre><code>$ kubectl patch mycrd.example.com test --type=json -p '[{"op": "replace", "path": "/status/foo", "value": "bar"}]'   
The  "" is invalid
</code></pre>

<p><strong>What are possible reasons for this error to occur? What options to I have for further debugging?</strong></p>

helmbert
<p>Found the (or at least, a partial) answer while still typing the question...</p>
<p><strong>The Kubernetes API server will not recursively create nested objects for a JSON patch input.</strong> This behaviour is consistent with the <a href="https://www.rfc-editor.org/rfc/rfc6902#appendix-A.12" rel="nofollow noreferrer">JSON Patch specification in RFC 6902, section A.12</a>:</p>
<blockquote>
<p><strong>A.12.  Adding to a Nonexistent Target</strong></p>
<p>An example target JSON document:</p>
<pre><code>{ &quot;foo&quot;: &quot;bar&quot; }
</code></pre>
<p>A JSON Patch document:</p>
<pre><code>[
  { &quot;op&quot;: &quot;add&quot;, &quot;path&quot;: &quot;/baz/bat&quot;, &quot;value&quot;: &quot;qux&quot; }
]
</code></pre>
<p>This JSON Patch document, applied to the target JSON document above,
would result in an error (therefore, it would not be applied),
because the &quot;add&quot; operation's target location that references neither
the root of the document, nor a member of an existing object, nor a
member of an existing array.</p>
</blockquote>
<p>This is why the original request fails, when the Custom Resources does not have a <code>.status</code> property to begin with. The following two subsequent calls (the second one being the original one) will complete successfully:</p>
<pre><code>$ kubectl patch mycrd.example.com test --type=json \
    -p '[{&quot;op&quot;: &quot;replace&quot;, &quot;path&quot;: &quot;/status&quot;, &quot;value&quot;: {}}]'
mycrd.example.com/test patched
$ kubectl patch mycrd.example.com test --type=json \
    -p '[{&quot;op&quot;: &quot;replace&quot;, &quot;path&quot;: &quot;/status/foo&quot;, &quot;value&quot;: &quot;bar&quot;}]'
mycrd.example.com/test patched
</code></pre>
<p>Obviously, <code>replace</code>ing the entire <code>.status</code> property with <code>{}</code> is not a good idea if that property already contains data that you want to keep.</p>
<p>A suitable alternative to a JSON patch in this scenario is a <a href="https://www.rfc-editor.org/rfc/rfc7386" rel="nofollow noreferrer">JSON Merge Patch</a>:</p>
<pre><code>PATCH /apis/example.com/v1alpha1/namespaces/default/mycrd/test HTTP/1.1
Accept: application/json
Content-Type: application/merge-patch+json
[other headers omitted for brevity...]

{
  &quot;status&quot;: {
    &quot;foo&quot;: &quot;bar&quot;
  }
}
</code></pre>
<p>Or, alternatively, using <code>kubectl</code>:</p>
<pre><code>$ kubectl patch mycrd.example.com test --type=merge \
    -p '{&quot;status&quot;: {&quot;foo&quot;: &quot;bar&quot;}}'
mycrd.example.com/test patched
</code></pre>
