<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Souvik Pramanik</title>
    <description>The latest articles on DEV Community by Souvik Pramanik (@jsonutiltools).</description>
    <link>https://dev.to/jsonutiltools</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4092884%2F33fb9966-5d85-4242-8fa7-e531c48c0e5e.png</url>
      <title>DEV Community: Souvik Pramanik</title>
      <link>https://dev.to/jsonutiltools</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jsonutiltools"/>
    <language>en</language>
    <item>
      <title>JSONPath Cheat Sheet: Syntax, Examples &amp; Common Mistakes</title>
      <dc:creator>Souvik Pramanik</dc:creator>
      <pubDate>Tue, 01 Sep 2026 23:42:14 +0000</pubDate>
      <link>https://dev.to/jsonutiltools/jsonpath-cheat-sheet-syntax-examples-common-mistakes-2h4b</link>
      <guid>https://dev.to/jsonutiltools/jsonpath-cheat-sheet-syntax-examples-common-mistakes-2h4b</guid>
      <description>&lt;p&gt;JSONPath looks simple until you actually need a filter, a slice, or a recursive match - then the handful of symbols that looked obvious start behaving unpredictably. This is a complete reference: every operator with a working example, a real query built step by step, the mistakes that most often cause a silent empty result, and how JSONPath stacks up against JMESPath and XPath.&lt;/p&gt;

&lt;h2&gt;
  
  
  Full syntax reference
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Syntax&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Root of the document - every expression starts here&lt;/td&gt;
&lt;td&gt;&lt;code&gt;$&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;.prop&lt;/code&gt; / &lt;code&gt;['prop']&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Child property, by dot or bracket notation&lt;/td&gt;
&lt;td&gt;&lt;code&gt;$.user.name&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[*]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Wildcard - all items in an array, or all properties of an object&lt;/td&gt;
&lt;td&gt;&lt;code&gt;$.items[*]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;..&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Recursive descent - matches a property at any depth&lt;/td&gt;
&lt;td&gt;&lt;code&gt;$..price&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;[0]&lt;/code&gt;, &lt;code&gt;[-1]&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Index into an array (some libraries support negative indices)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;$.items[0]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[0,2,5]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Union - multiple indices or property names at once&lt;/td&gt;
&lt;td&gt;&lt;code&gt;$.items[0,2,5]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[start:end:step]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Array slice, end-exclusive, step optional&lt;/td&gt;
&lt;td&gt;&lt;code&gt;$.items[1:5:2]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;[?(&amp;lt;expr&amp;gt;)]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Filter - keep only elements where &lt;code&gt;&amp;lt;expr&amp;gt;&lt;/code&gt; is true&lt;/td&gt;
&lt;td&gt;&lt;code&gt;$.items[?(@.price &amp;lt; 10)]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;@&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The current element being tested, used inside a filter&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@.inStock === true&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;=~ /regex/i&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Regex match inside a filter (library extension, not core spec)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@.name =~ /^a/i&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; / `\&lt;/td&gt;
&lt;td&gt;\&lt;/td&gt;
&lt;td&gt;`&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Worked example: querying a real API-shaped response
&lt;/h2&gt;

&lt;p&gt;Say an API returns this order history payload:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"customer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Alex"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"orders"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;101&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"shipped"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"total"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;42.50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"items"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"sku"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"A1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"qty"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;102&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pending"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"total"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;15.00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"items"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"sku"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"B4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"qty"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;103&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"shipped"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"total"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;8.25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"items"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"sku"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"A1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"qty"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Build the query one requirement at a time:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;"Give me every order total."&lt;/strong&gt; Walk from the root into the array and grab the field: &lt;code&gt;$.orders[*].total&lt;/code&gt; → &lt;code&gt;[42.50, 15.00, 8.25]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Only shipped orders."&lt;/strong&gt; Add a filter before drilling into the field: &lt;code&gt;$.orders[?(@.status === 'shipped')]&lt;/code&gt; → the two matching order objects&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Only shipped orders over $10."&lt;/strong&gt; Combine two conditions with &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;: &lt;code&gt;$.orders[?(@.status === 'shipped' &amp;amp;&amp;amp; @.total &amp;gt; 10)]&lt;/code&gt; → just order &lt;code&gt;101&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Just the SKUs from those orders, wherever they appear."&lt;/strong&gt; Recursive descent skips having to know the exact nesting depth: &lt;code&gt;$.orders[?(@.status === 'shipped')]..sku&lt;/code&gt; → &lt;code&gt;["A1", "A1"]&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's the general pattern for any JSONPath query: start at &lt;code&gt;$&lt;/code&gt;, narrow with a filter as early as possible (it's cheaper to filter the array once than to grab everything and post-process), then drill into the exact field you need.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mistakes that cause a silent empty result
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Forgetting the leading &lt;code&gt;$&lt;/code&gt;.&lt;/strong&gt; Every valid expression starts at the root - &lt;code&gt;orders[*].total&lt;/code&gt; without the &lt;code&gt;$&lt;/code&gt; is not a valid path in most libraries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Comparing a number to a quoted string in a filter.&lt;/strong&gt; &lt;code&gt;@.id == "101"&lt;/code&gt; when &lt;code&gt;id&lt;/code&gt; is a number will not match - drop the quotes: &lt;code&gt;@.id == 101&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Assuming &lt;code&gt;$..price&lt;/code&gt; and &lt;code&gt;$.price&lt;/code&gt; are the same.&lt;/strong&gt; The single-dot version only matches &lt;code&gt;price&lt;/code&gt; directly under the root; if it's nested, you need the recursive &lt;code&gt;..&lt;/code&gt; form.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Using a property with a dot or space without bracket notation.&lt;/strong&gt; &lt;code&gt;$.display name&lt;/code&gt; breaks - use &lt;code&gt;$['display name']&lt;/code&gt; instead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not confirming the array vs. object level first.&lt;/strong&gt; If a path returns nothing, back it off one segment at a time (&lt;code&gt;$.orders&lt;/code&gt;, then &lt;code&gt;$.orders[*]&lt;/code&gt;, then add the filter) to see exactly where it stops matching.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  JSONPath vs. JMESPath vs. XPath
&lt;/h2&gt;

&lt;p&gt;All three are query languages for structured data, but they're not interchangeable syntax for the same thing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;JSONPath&lt;/strong&gt; - the most common choice for querying JSON in JavaScript/Node tooling and API testing tools; uses &lt;code&gt;$&lt;/code&gt;, &lt;code&gt;[?()]&lt;/code&gt;, &lt;code&gt;..&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JMESPath&lt;/strong&gt; - used heavily in AWS CLI/SDK output filtering (&lt;code&gt;--query&lt;/code&gt;); has its own pipe-based syntax (&lt;code&gt;|&lt;/code&gt;) and built-in functions (&lt;code&gt;sort_by()&lt;/code&gt;, &lt;code&gt;contains()&lt;/code&gt;) that JSONPath doesn't have.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;XPath&lt;/strong&gt; - the original of the three, built for XML, with axis-based navigation (&lt;code&gt;//&lt;/code&gt;, &lt;code&gt;parent::&lt;/code&gt;) that predates JSON entirely.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you already know one, the other two feel roughly similar in spirit - "select nodes matching a pattern" - but none of the operators are directly transferable; check the target tool's docs rather than assuming JSONPath syntax works in a JMESPath-based tool like the AWS CLI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;Paste your own JSON into the &lt;a href="https://www.json-util.com/jsonpath" rel="noopener noreferrer"&gt;JSONPath Evaluator&lt;/a&gt; and test any expression from this cheat sheet directly against it - entirely in your browser, nothing uploaded.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Is JSONPath an official standard?&lt;/strong&gt;&lt;br&gt;
There's an RFC (RFC 9535) that standardizes a core JSONPath syntax, but many libraries - including most JavaScript ones - predate it and add their own extensions (like &lt;code&gt;=~&lt;/code&gt; regex filters). Stick to what your specific library documents if you hit inconsistent behavior between implementations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why does my filter expression return nothing?&lt;/strong&gt;&lt;br&gt;
The single most common cause is an operator or type mismatch inside &lt;code&gt;[?()]&lt;/code&gt; - for example comparing a number field to a quoted string, or forgetting that &lt;code&gt;@&lt;/code&gt; refers to the current item being tested, not the root. Isolate the problem by first running the path without the filter to confirm you're even at the right array.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's the difference between &lt;code&gt;$.a.b&lt;/code&gt; and &lt;code&gt;$..b&lt;/code&gt;?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;$.a.b&lt;/code&gt; is an exact path - it only matches &lt;code&gt;b&lt;/code&gt; directly under &lt;code&gt;a&lt;/code&gt;. &lt;code&gt;$..b&lt;/code&gt; is recursive descent - it matches a property named &lt;code&gt;b&lt;/code&gt; anywhere in the document, at any depth. The second is more powerful but slower and easier to get unexpected matches from on a large document.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can JSONPath modify or delete data, not just read it?&lt;/strong&gt;&lt;br&gt;
The JSONPath language itself is read-only - it selects and returns matching values. Some libraries add write/delete helpers on top, but that's a library-specific extension, not part of JSONPath itself.&lt;/p&gt;

</description>
      <category>json</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Validating OpenAI &amp; Anthropic Tool-Calling Schemas</title>
      <dc:creator>Souvik Pramanik</dc:creator>
      <pubDate>Mon, 24 Aug 2026 19:23:25 +0000</pubDate>
      <link>https://dev.to/jsonutiltools/validating-openai-anthropic-tool-calling-schemas-535</link>
      <guid>https://dev.to/jsonutiltools/validating-openai-anthropic-tool-calling-schemas-535</guid>
      <description>&lt;p&gt;Tool/function calling only works as well as the schema behind it. A structurally valid schema can still make an agent call your tool wrong — and a subtly broken one can fail silently. This post covers what actually goes wrong, how to catch it before it reaches a live model, and a worked example.&lt;/p&gt;

&lt;h2&gt;
  
  
  The two formats, side by side
&lt;/h2&gt;

&lt;p&gt;OpenAI and Anthropic both wrap a standard JSON Schema in a tool/function definition — they just nest it under a different field name.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OpenAI (function calling):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"get_weather"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Get the current weather for a given location."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"location"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"City and state, e.g. San Francisco, CA"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"unit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"enum"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"celsius"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fahrenheit"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"required"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"location"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"additionalProperties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Anthropic (tool use):&lt;/strong&gt; identical shape, just &lt;code&gt;input_schema&lt;/code&gt; instead of &lt;code&gt;parameters&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"get_weather"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Get the current weather for a given location."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"input_schema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"location"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"unit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"enum"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"celsius"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fahrenheit"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"required"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"location"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"additionalProperties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Five things that go wrong — and are easy to miss
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Root type isn't "object".&lt;/strong&gt; Both providers expect tool arguments to arrive as a JSON object. A schema whose root &lt;code&gt;type&lt;/code&gt; is anything else gets rejected or behaves unpredictably — a one-line fix, but the single most common structural mistake.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Missing or vague &lt;code&gt;description&lt;/code&gt; fields.&lt;/strong&gt; Not a JSON Schema violation — &lt;code&gt;description&lt;/code&gt; isn't required by the spec — but it's what the model actually reads to decide when and how to call the tool, and what to put in each argument. A schema that's technically valid but under-described leads to wrong calls, not errors.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;No &lt;code&gt;additionalProperties: false&lt;/code&gt;.&lt;/strong&gt; Without it, a model that hallucinates an extra argument still passes validation. Setting it to &lt;code&gt;false&lt;/code&gt; catches the hallucination immediately instead of letting it reach your function's implementation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Overly nested or ambiguous schemas.&lt;/strong&gt; Deep nesting, ambiguous &lt;code&gt;oneOf&lt;/code&gt; branches, or a huge flat list of optional fields all increase the model's chance of guessing wrong. Flatter, more explicit schemas produce more reliable calls.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Enum values that don't match what you actually accept.&lt;/strong&gt; An &lt;code&gt;enum&lt;/code&gt; that's stale relative to your function's real implementation is a silent mismatch — the schema will validate, but the call can still fail downstream.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  A pre-deploy checklist
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Is the whole tool definition valid JSON?&lt;/li&gt;
&lt;li&gt;Are &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;description&lt;/code&gt; both present and specific?&lt;/li&gt;
&lt;li&gt;Is the parameter schema's root &lt;code&gt;type&lt;/code&gt; set to &lt;code&gt;"object"&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;Is &lt;code&gt;additionalProperties: false&lt;/code&gt; set, unless you have a specific reason not to?&lt;/li&gt;
&lt;li&gt;Does the parameter schema actually compile as valid JSON Schema (no typos in keywords, correct nesting)?&lt;/li&gt;
&lt;li&gt;Does a realistic sample arguments payload — the kind of JSON the model would actually send — satisfy the schema?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All six of these are checkable offline, without a live model call. I built a free tool that runs exactly this checklist: &lt;a href="https://www.json-util.com/ai-tool-schema-validator" rel="noopener noreferrer"&gt;AI Tool / Function Calling Schema Validator&lt;/a&gt; — paste a tool definition, pick OpenAI or Anthropic, and it validates structure, compiles the schema, and checks sample arguments against it, entirely in your browser, no API calls.&lt;/p&gt;

&lt;h2&gt;
  
  
  Worked example: fixing a broken schema
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Before&lt;/strong&gt; — technically parseable, but has three of the problems above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"search"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"q"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"limit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No &lt;code&gt;description&lt;/code&gt; (the model has almost nothing to go on), no root &lt;code&gt;type: "object"&lt;/code&gt;, no &lt;code&gt;required&lt;/code&gt;, and &lt;code&gt;limit&lt;/code&gt; has no type at all.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;After:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"search"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Search the product catalog by keyword and return matching items."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"q"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Search keywords"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"limit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"integer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"minimum"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"maximum"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Max results to return"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"required"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"q"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"additionalProperties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;Paste your own tool definition into the &lt;a href="https://www.json-util.com/ai-tool-schema-validator" rel="noopener noreferrer"&gt;AI Tool Schema Validator&lt;/a&gt; and run through this exact checklist automatically, including testing sample arguments against the compiled schema. Nothing is sent to OpenAI, Anthropic, or any server — it's a structural, offline check only.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>openai</category>
      <category>anthropic</category>
      <category>json</category>
    </item>
  </channel>
</rss>
