<?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: Mohammed Awny</title>
    <description>The latest articles on DEV Community by Mohammed Awny (@user_177da31cc3).</description>
    <link>https://dev.to/user_177da31cc3</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%2F4137543%2Ffb257c9f-3b19-4c41-9789-1ecb60009210.png</url>
      <title>DEV Community: Mohammed Awny</title>
      <link>https://dev.to/user_177da31cc3</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/user_177da31cc3"/>
    <language>en</language>
    <item>
      <title>Why {"id":1}{"id":2} fails JSON.parse() — and when to wrap it in an array</title>
      <dc:creator>Mohammed Awny</dc:creator>
      <pubDate>Sat, 26 Sep 2026 16:16:08 +0000</pubDate>
      <link>https://dev.to/user_177da31cc3/why-id1id2-fails-jsonparse-and-when-to-wrap-it-in-an-array-25n3</link>
      <guid>https://dev.to/user_177da31cc3/why-id1id2-fails-jsonparse-and-when-to-wrap-it-in-an-array-25n3</guid>
      <description>&lt;p&gt;If you copy two JSON objects from a log, an AI response, or two API outputs, you may end up with this:&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="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&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;Each object is valid on its own. Together they are &lt;strong&gt;not one JSON document&lt;/strong&gt;. &lt;code&gt;JSON.parse()&lt;/code&gt; reads the first object, then encounters more content where it expects the input to end. In recent V8 versions you may see “Unexpected non-whitespace character after JSON.” In Python, &lt;code&gt;json.loads()&lt;/code&gt; often reports “Extra data.”&lt;/p&gt;

&lt;p&gt;The right fix depends on what the two objects represent.&lt;/p&gt;

&lt;h2&gt;
  
  
  One collection? Make an array
&lt;/h2&gt;

&lt;p&gt;If these are two entries in a single document, wrap them in brackets and separate them with a comma:&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="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&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="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&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;Now &lt;code&gt;JSON.parse()&lt;/code&gt; returns an array of two entries. This is what you want for a JSON file or a single API response containing a list. Do not blindly insert a comma between objects without the array: &lt;code&gt;{"id":1},{"id":2}&lt;/code&gt; is still not a valid single JSON document.&lt;/p&gt;

&lt;h2&gt;
  
  
  Separate events? Keep one record per line
&lt;/h2&gt;

&lt;p&gt;Some logs use &lt;strong&gt;NDJSON&lt;/strong&gt; (newline-delimited JSON): each line is an independent JSON value. That format is useful for event streams, but the whole file is not a single JSON document:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{"id":1}
{"id":2}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Parse lines separately when your producer really guarantees one complete JSON value per line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;records&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;raw&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\r?\n&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That snippet is not suitable for pretty-printed, multiline objects or incomplete stream chunks. Use a proper streaming parser for those. Converting an event stream into one array also changes its meaning and forces you to hold the collection in memory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before applying an automatic repair
&lt;/h2&gt;

&lt;p&gt;Check that both objects are complete and that you intend a collection. If the second object ends halfway through a string, the missing data cannot be inferred. And if the response starts with &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt;, you likely fetched an error page rather than JSON; inspect the HTTP response instead of changing its syntax.&lt;/p&gt;

&lt;p&gt;I maintain QuickTiny. Its free &lt;a href="https://quicktinyv2.vercel.app/json-formatter?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=json_objects" rel="noopener noreferrer"&gt;JSON formatter and validator&lt;/a&gt; detected the exact &lt;code&gt;{"id":1}{"id":2}&lt;/code&gt; example above and offered to wrap the two complete objects in an array. I checked the result in the browser: &lt;code&gt;[{"id":1},{"id":2}]&lt;/code&gt; is valid. Use it only when an array matches your data model; it does not repair truncated data.&lt;/p&gt;

&lt;p&gt;Have you seen concatenated objects in an API response, an event log, or an AI output? The origin usually tells you which representation is correct.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>json</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Why Shopify Rejects a Small Product Image: 25 MP vs 20 MB</title>
      <dc:creator>Mohammed Awny</dc:creator>
      <pubDate>Wed, 23 Sep 2026 16:34:53 +0000</pubDate>
      <link>https://dev.to/user_177da31cc3/why-shopify-rejects-a-small-product-image-25-mp-vs-20-mb-1j4m</link>
      <guid>https://dev.to/user_177da31cc3/why-shopify-rejects-a-small-product-image-25-mp-vs-20-mb-1j4m</guid>
      <description>&lt;p&gt;A product image can fail a Shopify upload even when its file is only a few megabytes. The reason: &lt;strong&gt;file size and pixel count are different limits&lt;/strong&gt;. Compressing bytes will not fix an image that has too many pixels.&lt;/p&gt;

&lt;p&gt;I ran a small upload test with product images in a live Shopify store and checked the result against &lt;a href="https://help.shopify.com/en/manual/products/product-media/product-media-types" rel="noopener noreferrer"&gt;Shopify's product-media documentation&lt;/a&gt;. The documentation says product and collection images can have up to 25 megapixels (its example is 5000 × 5000 pixels) and must be &lt;strong&gt;smaller than 20 MB&lt;/strong&gt;. These figures are for product and collection media; other upload contexts can have different requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the upload test showed
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Image&lt;/th&gt;
&lt;th&gt;Pixel count&lt;/th&gt;
&lt;th&gt;File size&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;5000 × 5000&lt;/td&gt;
&lt;td&gt;25.00 MP&lt;/td&gt;
&lt;td&gt;Under 20 MB&lt;/td&gt;
&lt;td&gt;Accepted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5200 × 5200&lt;/td&gt;
&lt;td&gt;27.04 MP&lt;/td&gt;
&lt;td&gt;Under 20 MB&lt;/td&gt;
&lt;td&gt;Rejected for megapixels&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3200 × 3200&lt;/td&gt;
&lt;td&gt;10.24 MP&lt;/td&gt;
&lt;td&gt;29.9 MB&lt;/td&gt;
&lt;td&gt;Rejected for file size&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The 5200 × 5200 image failed with a megapixel error. The 3200 × 3200 image passed the pixel-count test but failed the file-size test. In each case, changing the wrong property would leave the actual problem in place.&lt;/p&gt;

&lt;p&gt;I then resized the rejected 5200 × 5200 image to &lt;strong&gt;4898 × 4898 (23.99 MP)&lt;/strong&gt; and uploaded that output; Shopify accepted it. Separately, compressing the rejected 29.9 MB image to &lt;strong&gt;8.81 MB&lt;/strong&gt; without changing its 3200 × 3200 dimensions produced an accepted upload. The &lt;a href="https://quicktinyv2.vercel.app/shopify-image-upload-limits-test-2026" rel="noopener noreferrer"&gt;full test table and method&lt;/a&gt; include the exact rejection messages and downloadable data.&lt;/p&gt;

&lt;h2&gt;
  
  
  A quick preflight in the browser
&lt;/h2&gt;

&lt;p&gt;Before uploading, inspect both properties:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;megapixels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;_000_000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;megabytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;_000_000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;megapixels&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;megabytes&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If pixel count is over the limit, &lt;strong&gt;resize dimensions&lt;/strong&gt;, preserving aspect ratio. If bytes are over the limit, &lt;strong&gt;compress or change the export format&lt;/strong&gt;. If both are over, do both. Leave some margin below the limit rather than aiming for the precise boundary. This simple preflight only covers those two checks; a valid file can still run into format or other upload problems.&lt;/p&gt;

&lt;p&gt;For a non-square image, multiply its width and height: 6000 × 4000 is 24 MP. It passed in our product uploader test, even though one side exceeds the 5000-pixel square example. That is why total pixels are more useful than memorizing one width or height.&lt;/p&gt;

&lt;p&gt;If you want to test one product photo without writing code, the &lt;a href="https://quicktinyv2.vercel.app/compress-product-images-for-shopify" rel="noopener noreferrer"&gt;free Shopify image checker&lt;/a&gt; reports which limit it hits and can fix the image locally in your browser. It is an independent tool, not a Shopify app or Shopify-endorsed product; no account or upload to QuickTiny's server is required for the single-image checker.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scope:&lt;/strong&gt; This was an empirical test on one store's product-image uploader in September 2026. Shopify can change its rules, so check its current documentation when you rely on a limit for production. Have you seen an image rejected for a reason other than bytes or megapixels? I'd be interested in the exact error message.&lt;/p&gt;

</description>
      <category>shopify</category>
      <category>webdev</category>
      <category>ecommerce</category>
    </item>
    <item>
      <title>Why “Unexpected token '&lt;'” is usually an HTTP problem</title>
      <dc:creator>Mohammed Awny</dc:creator>
      <pubDate>Wed, 23 Sep 2026 13:31:11 +0000</pubDate>
      <link>https://dev.to/user_177da31cc3/why-unexpected-token-is-usually-an-http-problem-3o0a</link>
      <guid>https://dev.to/user_177da31cc3/why-unexpected-token-is-usually-an-http-problem-3o0a</guid>
      <description>&lt;p&gt;If &lt;code&gt;response.json()&lt;/code&gt; throws &lt;code&gt;Unexpected token '&amp;lt;'&lt;/code&gt;, inspect the response before changing your JSON parser. The first character is often the start of &lt;code&gt;&amp;lt;!doctype html&amp;gt;&lt;/code&gt;: your request received an HTML page.&lt;/p&gt;

&lt;p&gt;This can happen when an API route returns a 404 page, an authentication flow redirects to a login page, or a frontend fallback serves &lt;code&gt;index.html&lt;/code&gt; for an unknown path. A 200 status alone does not prove the response is JSON.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read the response once
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;contentType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;content-type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;contentType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;`Expected JSON; got HTTP &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;contentType&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;unknown content type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; at &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;. Body: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;160&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;`Invalid JSON at &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;cause&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;products&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/products&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read the body with &lt;code&gt;text()&lt;/code&gt; &lt;em&gt;once&lt;/em&gt;. Calling &lt;code&gt;response.json()&lt;/code&gt; afterward on the same response fails because the body has already been consumed. Parsing the captured string with &lt;code&gt;JSON.parse(raw)&lt;/code&gt; avoids that trap.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to check next
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Look at &lt;strong&gt;HTTP status&lt;/strong&gt;, &lt;strong&gt;final URL&lt;/strong&gt;, and &lt;strong&gt;Content-Type&lt;/strong&gt; in the Network tab. A login redirect can change the final URL; a missing route can return an HTML error page.&lt;/li&gt;
&lt;li&gt;If the response is HTML, fix the endpoint, authentication, routing, or server response. Editing a formatter cannot turn an HTML page into the intended API data.&lt;/li&gt;
&lt;li&gt;If it really is JSON but parsing fails, inspect the returned text around the position in the error. Common mistakes include trailing commas, single-quoted strings, and an unquoted property name. Those are not valid JSON even though they can look like JavaScript object literals.&lt;/li&gt;
&lt;li&gt;Do not automatically “repair” incomplete or truncated data. Retry the request or fix the producer; guessing the missing portion can silently change the meaning.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For a quick, browser-based inspection of an actual JSON payload, &lt;a href="https://quicktinyv2.vercel.app/json-formatter" rel="noopener noreferrer"&gt;QuickTiny's JSON Formatter&lt;/a&gt; shows parse errors and handles some unambiguous formatting mistakes. I maintain QuickTiny. Check sensitive payloads against your own data-handling policy before using any tool.&lt;/p&gt;

&lt;p&gt;The key diagnostic step is simple: &lt;strong&gt;verify what the server sent before assuming the parser is broken.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>api</category>
    </item>
    <item>
      <title>How I Detect JSON, Base64, URLs, and Timestamps Without AI</title>
      <dc:creator>Mohammed Awny</dc:creator>
      <pubDate>Tue, 22 Sep 2026 16:45:23 +0000</pubDate>
      <link>https://dev.to/user_177da31cc3/how-i-detect-json-base64-urls-and-timestamps-without-ai-560p</link>
      <guid>https://dev.to/user_177da31cc3/how-i-detect-json-base64-urls-and-timestamps-without-ai-560p</guid>
      <description>&lt;p&gt;Format detection sounds simple until the inputs overlap.&lt;/p&gt;

&lt;p&gt;A numeric string might be a Unix timestamp, an identifier, or valid-looking Base64. A normal word can use only Base64 characters. JSON often arrives wrapped in Markdown fences or surrounded by an LLM explanation.&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;QuickTiny Smart Actions&lt;/strong&gt;, I wanted the browser to suggest the right tool without uploading the pasted value or calling an AI model.&lt;/p&gt;

&lt;h2&gt;
  
  
  The detection order
&lt;/h2&gt;

&lt;p&gt;The order is intentional:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Valid JSON objects or arrays&lt;/li&gt;
&lt;li&gt;Fenced, wrapped, or conservatively repairable JSON&lt;/li&gt;
&lt;li&gt;Plausible Unix timestamps in seconds or milliseconds&lt;/li&gt;
&lt;li&gt;URL-encoded text with valid percent escapes&lt;/li&gt;
&lt;li&gt;Base64 with additional plausibility checks&lt;/li&gt;
&lt;li&gt;Multiline or list-like text&lt;/li&gt;
&lt;li&gt;Plain text as the fallback&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Stronger signals run before weaker ones.&lt;/p&gt;

&lt;h2&gt;
  
  
  JSON first
&lt;/h2&gt;

&lt;p&gt;Strict parsing is the highest-confidence check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isJsonObjectOrArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;parsed&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;parsed&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The repair path is deliberately limited. It can remove Markdown fences, extract a complete object or array from surrounding text, remove trailing commas, and quote simple keys.&lt;/p&gt;

&lt;p&gt;It should not invent missing values or guess a schema.&lt;/p&gt;

&lt;h2&gt;
  
  
  Timestamps before Base64
&lt;/h2&gt;

&lt;p&gt;A loose Base64 regex will match many numeric strings. I exclude pure numbers from Base64 detection and test timestamps by magnitude first.&lt;/p&gt;

&lt;p&gt;The value must also fall within a plausible date range. That prevents every short integer from being labeled as a date.&lt;/p&gt;

&lt;h2&gt;
  
  
  Base64 needs more than a regex
&lt;/h2&gt;

&lt;p&gt;Character-set matching is only the beginning. The detector also checks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Minimum length&lt;/li&gt;
&lt;li&gt;Padding shape&lt;/li&gt;
&lt;li&gt;Impossible remainder lengths&lt;/li&gt;
&lt;li&gt;Whether decoding succeeds&lt;/li&gt;
&lt;li&gt;The proportion of printable decoded bytes&lt;/li&gt;
&lt;li&gt;Whether the input is only numeric&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even then, Base64 is a suggestion—not a certainty.&lt;/p&gt;

&lt;h2&gt;
  
  
  URL-encoded values
&lt;/h2&gt;

&lt;p&gt;The input must contain valid percent-encoded byte sequences, and decoding must succeed. A normal sentence containing a percent sign should not be routed to a URL decoder.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lists and plain text
&lt;/h2&gt;

&lt;p&gt;Multiline input is useful for cleaning, sorting, and duplicate removal. Everything else falls back to word counting, text cleanup, and case conversion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Privacy boundary
&lt;/h2&gt;

&lt;p&gt;All detection runs in the browser. QuickTiny records only categorical events such as “detected Base64,” never the pasted value.&lt;/p&gt;

&lt;p&gt;This is why deterministic heuristics were a better fit than an AI API for this feature: they are fast, explainable, local, and cheap.&lt;/p&gt;

&lt;h2&gt;
  
  
  The main lesson
&lt;/h2&gt;

&lt;p&gt;The goal is not to classify every string confidently. The goal is to provide a useful suggestion while keeping the user in control.&lt;/p&gt;

&lt;p&gt;Try the live detector:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://quicktinyv2.vercel.app/" rel="noopener noreferrer"&gt;https://quicktinyv2.vercel.app/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Full methodology:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://quicktinyv2.vercel.app/how-smart-actions-detects-pasted-content" rel="noopener noreferrer"&gt;https://quicktinyv2.vercel.app/how-smart-actions-detects-pasted-content&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you find a non-sensitive value that routes to the wrong tool, I’d genuinely like to see it.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>programming</category>
      <category>privacy</category>
    </item>
    <item>
      <title>I Built a Browser Tool That Detects What You Paste</title>
      <dc:creator>Mohammed Awny</dc:creator>
      <pubDate>Tue, 22 Sep 2026 12:08:50 +0000</pubDate>
      <link>https://dev.to/user_177da31cc3/i-built-a-browser-tool-that-detects-what-you-paste-334p</link>
      <guid>https://dev.to/user_177da31cc3/i-built-a-browser-tool-that-detects-what-you-paste-334p</guid>
      <description>&lt;p&gt;I kept switching between tiny web tools just to handle everyday developer tasks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Formatting JSON&lt;/li&gt;
&lt;li&gt;Decoding Base64&lt;/li&gt;
&lt;li&gt;Cleaning URLs&lt;/li&gt;
&lt;li&gt;Converting Unix timestamps&lt;/li&gt;
&lt;li&gt;Removing duplicate lines&lt;/li&gt;
&lt;li&gt;Transforming text&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I built &lt;strong&gt;QuickTiny&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The main feature is &lt;strong&gt;Smart Actions&lt;/strong&gt;: paste almost anything, and QuickTiny tries to recognize the content and suggest the right tool automatically.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Paste JSON → format and validate it&lt;/li&gt;
&lt;li&gt;Paste Base64 → decode it&lt;/li&gt;
&lt;li&gt;Paste a Unix timestamp → convert it&lt;/li&gt;
&lt;li&gt;Paste URL-encoded text → decode it&lt;/li&gt;
&lt;li&gt;Paste a list → clean, sort, or remove duplicates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything runs locally in the browser. There is no signup, and the pasted content is not uploaded.&lt;/p&gt;

&lt;p&gt;QuickTiny currently includes 13 small browser tools. I’m trying to keep the interface fast and focused instead of turning it into a crowded toolbox.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try it:&lt;/strong&gt; &lt;a href="https://quicktinyv2.vercel.app" rel="noopener noreferrer"&gt;https://quicktinyv2.vercel.app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Watch the short Smart Actions demo:&lt;/strong&gt; &lt;a href="https://quicktinyv2.vercel.app/quicktiny-smart-actions-demo.mp4" rel="noopener noreferrer"&gt;https://quicktinyv2.vercel.app/quicktiny-smart-actions-demo.mp4&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’d appreciate honest feedback—especially examples that Smart Actions detects incorrectly or tools you repeatedly need during development.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>javascript</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
