<?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: Rasika Dangamuwa</title>
    <description>The latest articles on DEV Community by Rasika Dangamuwa (@rasika_dangamuwa_ed1074fe).</description>
    <link>https://dev.to/rasika_dangamuwa_ed1074fe</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%2F4025318%2F0ed5e5b1-1a13-4e6f-9289-fc5142aca273.png</url>
      <title>DEV Community: Rasika Dangamuwa</title>
      <link>https://dev.to/rasika_dangamuwa_ed1074fe</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rasika_dangamuwa_ed1074fe"/>
    <language>en</language>
    <item>
      <title>JSON to Go Structs: 5 Edge Cases That Break Type Safety in Golang</title>
      <dc:creator>Rasika Dangamuwa</dc:creator>
      <pubDate>Mon, 10 Aug 2026 13:00:46 +0000</pubDate>
      <link>https://dev.to/rasika_dangamuwa_ed1074fe/json-to-go-structs-5-edge-cases-that-break-type-safety-in-golang-5d</link>
      <guid>https://dev.to/rasika_dangamuwa_ed1074fe/json-to-go-structs-5-edge-cases-that-break-type-safety-in-golang-5d</guid>
      <description>&lt;p&gt;Go's standard &lt;code&gt;encoding/json&lt;/code&gt; package requires predefined struct types to deserialize JSON data safely. While Go's strong typing prevents runtime surprises once data is parsed, converting arbitrary or nested JSON objects into idiomatic Go structs is full of subtle traps.&lt;/p&gt;

&lt;p&gt;When consuming third-party APIs or legacy endpoints, naive struct generation frequently introduces subtle bugs—from silent zero-value overwrites to numeric precision loss. Here are five common edge cases in JSON-to-Go struct mapping and how to handle them cleanly.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. &lt;code&gt;null&lt;/code&gt;, Missing Fields, and Zero-Value Ambiguity
&lt;/h3&gt;

&lt;p&gt;In JSON, there is a distinct difference between a key having a value of &lt;code&gt;null&lt;/code&gt;, a key being entirely omitted, and a key having a zero value (like &lt;code&gt;0&lt;/code&gt;, &lt;code&gt;false&lt;/code&gt;, or &lt;code&gt;""&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Consider this JSON response:&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;"user_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;1042&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"bio"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"is_active"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If mapped to a standard Go struct:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;UserResponse&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;UserID&lt;/span&gt;   &lt;span class="kt"&gt;int&lt;/span&gt;    &lt;span class="s"&gt;`json:"user_id"`&lt;/span&gt;
    &lt;span class="n"&gt;Bio&lt;/span&gt;      &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"bio"`&lt;/span&gt;
    &lt;span class="n"&gt;IsActive&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;   &lt;span class="s"&gt;`json:"is_active"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Go will unmarshal &lt;code&gt;"bio": null&lt;/code&gt; into an empty string &lt;code&gt;""&lt;/code&gt;. Your application logic can no longer distinguish between a user who set their bio to empty versus a user whose bio is &lt;code&gt;null&lt;/code&gt; (or unconfigured). &lt;/p&gt;

&lt;p&gt;To preserve &lt;code&gt;null&lt;/code&gt; semantics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use pointer types (e.g., &lt;code&gt;Bio *string&lt;/code&gt;), where &lt;code&gt;null&lt;/code&gt; unmarshals to &lt;code&gt;nil&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Or use &lt;code&gt;sql.NullString&lt;/code&gt; / custom unmarshalers if pointer allocations are a performance concern.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  2. Large Integers and &lt;code&gt;float64&lt;/code&gt; Precision Loss
&lt;/h3&gt;

&lt;p&gt;By default, when Go unmarshals JSON numbers into an untyped &lt;code&gt;interface{}&lt;/code&gt; or &lt;code&gt;any&lt;/code&gt;, it parses all numbers as &lt;code&gt;float64&lt;/code&gt;. This creates major issues with 64-bit integer IDs (like Twitter Snowflakes or 64-bit database primary keys):&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;"transaction_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;9223372036854775807&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;If unmarshaled into &lt;code&gt;float64&lt;/code&gt;, IEEE 754 floating-point representation loses precision beyond $2^{53} - 1$ ($9,007,199,254,740,991$), silently corrupting the ID.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt; Always explicitly declare &lt;code&gt;int64&lt;/code&gt; or &lt;code&gt;uint64&lt;/code&gt; in your struct tags rather than relying on generic map types:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;FinancialRecord&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;TransactionID&lt;/span&gt; &lt;span class="kt"&gt;int64&lt;/span&gt; &lt;span class="s"&gt;`json:"transaction_id,string"`&lt;/span&gt; &lt;span class="c"&gt;// if passed as string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the upstream API returns large numbers directly as unquoted JSON integers, set &lt;code&gt;Decoder.UseNumber()&lt;/code&gt; when setting up your JSON decoder.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Mixed-Type Arrays and Polymorphic JSON
&lt;/h3&gt;

&lt;p&gt;REST APIs sometimes return arrays containing heterogeneous data types or polymorphic objects:&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;"events"&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;"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;"click"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"x"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"y"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;450&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;"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;"input"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"hello world"&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;Attempting to model &lt;code&gt;events&lt;/code&gt; as &lt;code&gt;[]Event&lt;/code&gt; with a single struct will force optional fields with &lt;code&gt;omitempty&lt;/code&gt; across all payload variants. When working with complex API payloads, using an in-browser utility like &lt;a href="https://nutilz.com/json-to-go" rel="noopener noreferrer"&gt;Nutilz JSON to Go&lt;/a&gt; allows you to instantly generate struct definitions with proper struct tags and nested type inferencing without transmitting sensitive payload data to external servers.&lt;/p&gt;

&lt;p&gt;For polymorphic arrays in Go:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unmarshal into &lt;code&gt;[]json.RawMessage&lt;/code&gt; first.&lt;/li&gt;
&lt;li&gt;Inspect the &lt;code&gt;"type"&lt;/code&gt; discriminator field.&lt;/li&gt;
&lt;li&gt;Unmarshal each item into its specific concrete struct (&lt;code&gt;ClickEvent&lt;/code&gt; vs &lt;code&gt;InputEvent&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  4. Struct Tag Case Conventions and Acronym Collisions
&lt;/h3&gt;

&lt;p&gt;Go field names must be exported (capitalized) to be visible to &lt;code&gt;encoding/json&lt;/code&gt;. Automatic converters typically convert &lt;code&gt;snake_case&lt;/code&gt; JSON keys to &lt;code&gt;PascalCase&lt;/code&gt; Go field names.&lt;/p&gt;

&lt;p&gt;However, idiomatic Go prefers initialisms to remain uppercase (e.g., &lt;code&gt;URL&lt;/code&gt;, &lt;code&gt;HTTP&lt;/code&gt;, &lt;code&gt;ID&lt;/code&gt;, &lt;code&gt;UUID&lt;/code&gt;, &lt;code&gt;IP&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Anti-pattern&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Config&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ApiUrl&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"api_url"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Idiomatic Go&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Config&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;APIURL&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"api_url"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inconsistent naming can lead to confusion across teams and break linter rules like &lt;code&gt;golangci-lint&lt;/code&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. Overusing &lt;code&gt;omitempty&lt;/code&gt; on Boolean and Numeric Fields
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;omitempty&lt;/code&gt; struct tag instructs Go to skip serializing fields equal to their zero value. But for booleans and numbers, &lt;code&gt;false&lt;/code&gt; and &lt;code&gt;0&lt;/code&gt; are valid values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;AccountStatus&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;IsDisabled&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="s"&gt;`json:"is_disabled,omitempty"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;IsDisabled&lt;/code&gt; is &lt;code&gt;false&lt;/code&gt;, &lt;code&gt;json.Marshal&lt;/code&gt; will omit &lt;code&gt;is_disabled&lt;/code&gt; entirely from the JSON payload instead of outputting &lt;code&gt;"is_disabled": false&lt;/code&gt;. In Go 1.24+, the new &lt;code&gt;omitzero&lt;/code&gt; tag helps resolve zero-value vs empty-value ambiguities for structs implementing &lt;code&gt;isZero()&lt;/code&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Translating complex JSON structures into clean Go code requires careful attention to pointers, numeric precision, and field tags. Automated tooling can save significant developer time when bootstrapping these definitions. &lt;/p&gt;

&lt;p&gt;Whenever you are integrating a third-party API in Go, test your struct definitions against representative sample payloads. For fast client-side generation without backend data logging, try out &lt;a href="https://nutilz.com/json-to-go" rel="noopener noreferrer"&gt;Nutilz's JSON to Go converter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>go</category>
      <category>json</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Why Auto-Generated TypeScript Interfaces Fail in Production (and How to Fix Them)</title>
      <dc:creator>Rasika Dangamuwa</dc:creator>
      <pubDate>Mon, 10 Aug 2026 11:01:56 +0000</pubDate>
      <link>https://dev.to/rasika_dangamuwa_ed1074fe/why-auto-generated-typescript-interfaces-fail-in-production-and-how-to-fix-them-2cp7</link>
      <guid>https://dev.to/rasika_dangamuwa_ed1074fe/why-auto-generated-typescript-interfaces-fail-in-production-and-how-to-fix-them-2cp7</guid>
      <description>&lt;p&gt;When working with REST APIs, GraphQL endpoints, or third-party webhooks, front-end and full-stack developers constantly map raw JSON payloads into TypeScript interfaces. It is common practice to take a sample HTTP response from Postman or browser DevTools and pass it through a type converter to avoid handwriting dozens of interface fields.&lt;/p&gt;

&lt;p&gt;However, naive JSON-to-TypeScript conversion often introduces silent runtime bugs. A type generator creates types based purely on the specific JSON snippet provided at that moment. When production API responses inevitably introduce null values, omitted fields, or dynamic keys, your build-time type checks fail to protect you.&lt;/p&gt;

&lt;p&gt;Here are the critical edge cases in JSON-to-TypeScript type generation and how to handle them cleanly in your codebase.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The Confusion Between Nullable, Optional, and Undefined
&lt;/h3&gt;

&lt;p&gt;Consider a standard user profile 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;"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;1042&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"johndoe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"middle_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"bio"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Senior Software Engineer"&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;A basic converter will infer &lt;code&gt;middle_name&lt;/code&gt; as &lt;code&gt;any&lt;/code&gt; or &lt;code&gt;null&lt;/code&gt;. If a developer manually adjusts it to &lt;code&gt;middle_name?: string&lt;/code&gt;, they create a subtle flaw:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Problematic interface&lt;/span&gt;
&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;UserProfile&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="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;middle_name&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Means string | undefined&lt;/span&gt;
  &lt;span class="nl"&gt;bio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;In TypeScript, &lt;code&gt;middle_name?: string&lt;/code&gt; indicates that the key may be entirely absent from the object. But in JSON serialization:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;JSON.stringify({ middle_name: undefined })&lt;/code&gt; yields &lt;code&gt;{}&lt;/code&gt; (the key is removed).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;JSON.stringify({ middle_name: null })&lt;/code&gt; yields &lt;code&gt;{"middle_name": null}&lt;/code&gt; (the key exists with a null literal).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your frontend component checks &lt;code&gt;if ('middle_name' in user)&lt;/code&gt; or relies on &lt;code&gt;Object.keys()&lt;/code&gt;, &lt;code&gt;null&lt;/code&gt; and &lt;code&gt;undefined&lt;/code&gt; behave differently. The correct representation for explicit nulls in API responses is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;UserProfile&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="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;middle_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;bio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;h3&gt;
  
  
  2. Heterogeneous Arrays and Inferred Union Types
&lt;/h3&gt;

&lt;p&gt;APIs often return arrays containing items with varying schema versions or polymorphic payloads:&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;"events"&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;"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;"click"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"x"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"y"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;340&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;"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;"keypress"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Enter"&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;If you feed only the first item into a simple generator, you get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Event&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&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;When a &lt;code&gt;keypress&lt;/code&gt; event arrives in production, accessing &lt;code&gt;event.x&lt;/code&gt; will produce &lt;code&gt;undefined&lt;/code&gt; at runtime despite TypeScript claiming &lt;code&gt;x&lt;/code&gt; is a non-nullable &lt;code&gt;number&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To prevent this, supply a multi-element JSON array containing all event variants to your converter. An intelligent converter will infer a discriminated union:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;AppEvent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;keypress&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Number Precision and Large 64-Bit Integers
&lt;/h3&gt;

&lt;p&gt;JSON numbers are double-precision IEEE 754 floats. High-precision backend identifiers (such as Twitter Snowflake IDs or database 64-bit BigInts) cause data corruption when parsed into standard JavaScript numbers:&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;"transaction_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;9223372036854775807&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;In JavaScript, &lt;code&gt;JSON.parse()&lt;/code&gt; converts this to &lt;code&gt;9223372036854775808&lt;/code&gt; due to &lt;code&gt;Number.MAX_SAFE_INTEGER&lt;/code&gt; limits (9,007,199,254,740,991).&lt;/p&gt;

&lt;p&gt;When converting JSON to TypeScript, identify ID fields that exceed safe integer limits and ensure the API returns them as strings, or wrap them in branded string types:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;SnowflakeId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="na"&gt;__brand&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unique&lt;/span&gt; &lt;span class="nx"&gt;symbol&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Streamlining Your Interface Generation Workflow
&lt;/h3&gt;

&lt;p&gt;When building TypeScript applications, using an in-browser converter like the &lt;a href="https://nutilz.com/json-to-typescript" rel="noopener noreferrer"&gt;Nutilz JSON to TypeScript Converter&lt;/a&gt; speeds up initial interface drafting. Because conversion logic runs client-side in WebAssembly/JS without sending API payloads to an external backend, sensitive production JSON remains private.&lt;/p&gt;

&lt;p&gt;Once your base interfaces are generated:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Merge single-sample fields into optional (&lt;code&gt;?&lt;/code&gt;) or union types (&lt;code&gt;| null&lt;/code&gt;) based on API specifications.&lt;/li&gt;
&lt;li&gt;Abstract repeated response envelopes into generic interfaces: &lt;code&gt;interface ApiResponse&amp;lt;T&amp;gt; { data: T; status: number; }&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Validate runtime boundaries using Zod or Valibot for critical external endpoints.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Auto-generating TypeScript types from sample JSON responses saves time, but automated tools can only inspect the data you feed them. Always inspect edge cases—such as nullable fields, dynamic array structures, and numeric safety limits—to maintain strict type safety across your stack.&lt;/p&gt;

&lt;p&gt;For quick, private client-side interface drafting, tools like &lt;a href="https://nutilz.com/json-to-typescript" rel="noopener noreferrer"&gt;Nutilz&lt;/a&gt; offer immediate JSON-to-TypeScript conversion without requiring logins or external network calls.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>typescript</category>
      <category>javascript</category>
      <category>programming</category>
    </item>
    <item>
      <title>Why UUID v4 Is Killing Your Database Indexes (And How UUID v7 Fixes It)</title>
      <dc:creator>Rasika Dangamuwa</dc:creator>
      <pubDate>Mon, 10 Aug 2026 01:00:50 +0000</pubDate>
      <link>https://dev.to/rasika_dangamuwa_ed1074fe/why-uuid-v4-is-killing-your-database-indexes-and-how-uuid-v7-fixes-it-37cm</link>
      <guid>https://dev.to/rasika_dangamuwa_ed1074fe/why-uuid-v4-is-killing-your-database-indexes-and-how-uuid-v7-fixes-it-37cm</guid>
      <description>&lt;p&gt;If you have ever built a distributed system or microservice architecture, you have likely used Universally Unique Identifiers (UUIDs) for database primary keys. They solve the coordination problem instantly: any service can generate a unique key locally without talking to a central database or sequence generator.&lt;/p&gt;

&lt;p&gt;However, as your tables grow into millions of rows, you might notice a sudden degradation in insert performance, rising disk I/O, and aggressive memory consumption. The root cause is often the very ID strategy that enabled your distributed setup: standard UUID v4.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem: B-Tree Page Splits and Random Writes
&lt;/h3&gt;

&lt;p&gt;Most relational database engines, including PostgreSQL (B-Tree) and MySQL (InnoDB clustered indexes), store primary key indexes in balanced tree structures. These structures are optimized for sequential or near-sequential inserts.&lt;/p&gt;

&lt;p&gt;When you use an auto-incrementing integer (&lt;code&gt;SERIAL&lt;/code&gt; or &lt;code&gt;BIGINT&lt;/code&gt;), each new row is appended to the rightmost leaf node of the B-Tree index. This operation is fast and predictable:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The engine checks the rightmost page in buffer pool memory.&lt;/li&gt;
&lt;li&gt;If space exists, it writes the new index entry.&lt;/li&gt;
&lt;li&gt;Disk pages remain packed at near 100% fill factor.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;UUID v4, by design (RFC 4122), consists of 122 bits of pseudo-random data. When inserting rows with UUID v4 primary keys, new values are scattered randomly across the entire range of the B-Tree index.&lt;/p&gt;

&lt;p&gt;This randomness triggers frequent &lt;strong&gt;page splits&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When an insert hits a full index page (typically 8KB or 16KB), the database engine must allocate a new page.&lt;/li&gt;
&lt;li&gt;It moves half of the entries from the existing page into the new page to maintain sorting order.&lt;/li&gt;
&lt;li&gt;Both modified pages must be written back to disk, along with updates to parent node references in the tree.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At scale, this results in severe write amplification, index fragmentation (pages sitting 50% empty), and poor cache locality because working sets no longer fit in memory.&lt;/p&gt;

&lt;h3&gt;
  
  
  How UUID v7 Solves the Indexing Bottleneck
&lt;/h3&gt;

&lt;p&gt;Published in RFC 9562, UUID v7 introduces a time-ordered structure designed specifically for modern database workloads:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;First 48 bits&lt;/strong&gt;: Big-endian Unix timestamp in milliseconds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Next 12 bits&lt;/strong&gt;: Sub-millisecond precision or random counter bits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Remaining 68 bits&lt;/strong&gt;: Cryptographically strong pseudo-random data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because the leading 48 bits represent monotonically increasing time, UUID v7 values are lexicographically sortable. For database indexes, a UUID v7 behaves almost identically to an auto-incrementing integer during inserts: new keys arrive at the rightmost edge of the B-Tree.&lt;/p&gt;

&lt;p&gt;Here is a comparison of key layouts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;UUID v4: 9b1deb4d-3b7d-4149-9cc6-84776ad0c4e7  (Purely random)
UUID v7: 018f4a12-68b3-7649-b570-3d84931a7890  (Time-ordered prefix + random)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By switching to UUID v7, benchmarks across PostgreSQL and InnoDB show up to 8x higher insert throughput and a 40–50% reduction in index size compared to UUID v4.&lt;/p&gt;

&lt;p&gt;When prototyping schemas or testing migrations locally, you can quickly generate and compare different UUID formats using the free &lt;a href="https://nutilz.com/uuid-generator" rel="noopener noreferrer"&gt;Nutilz UUID Generator&lt;/a&gt;, which generates v4, v7, and namespace-based UUIDs directly in your browser.&lt;/p&gt;

&lt;h3&gt;
  
  
  Privacy and Security Tradeoffs
&lt;/h3&gt;

&lt;p&gt;While UUID v7 provides superior indexing performance, it is important to consider the trade-offs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Information Leakage&lt;/strong&gt;: Because the first 48 bits encode a timestamp, anyone observing a UUID v7 can extract the exact millisecond the record was created. In public-facing URLs or API tokens, this could leak sensitive operational metrics (such as daily user signup volume).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clock Drift Sensitivity&lt;/strong&gt;: If your server clocks drift backwards or experience NTP adjustments, monotonic ordering can be affected. Modern UUID v7 implementations handle this by incrementing counter bits during time collisions.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Summary of Best Practices
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Use UUID v7 for internal database primary keys&lt;/strong&gt;: Enjoy distributed ID generation without sacrificing B-Tree index performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use UUID v4 for public tokens and external IDs&lt;/strong&gt;: Keep creation timestamps hidden where privacy matters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Store as Native UUID or Binary(16)&lt;/strong&gt;: Avoid storing 36-character string representations (&lt;code&gt;CHAR(36)&lt;/code&gt;), which double storage overhead and slow down comparisons.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For quick testing, mock data generation, or formatting checks without writing local scripts, utilities like &lt;a href="https://nutilz.com/uuid-generator" rel="noopener noreferrer"&gt;Nutilz&lt;/a&gt; offer browser-based tools with zero data collection.&lt;/p&gt;

</description>
      <category>database</category>
      <category>postgres</category>
      <category>sql</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Converting cURL Commands to Production Code: 5 Edge Cases That Break API Calls</title>
      <dc:creator>Rasika Dangamuwa</dc:creator>
      <pubDate>Sun, 09 Aug 2026 23:00:46 +0000</pubDate>
      <link>https://dev.to/rasika_dangamuwa_ed1074fe/converting-curl-commands-to-production-code-5-edge-cases-that-break-api-calls-1hb9</link>
      <guid>https://dev.to/rasika_dangamuwa_ed1074fe/converting-curl-commands-to-production-code-5-edge-cases-that-break-api-calls-1hb9</guid>
      <description>&lt;p&gt;You copy a &lt;code&gt;curl&lt;/code&gt; command straight from Chrome DevTools or a third-party API provider's documentation. It runs perfectly in your terminal. But when you manually translate it into your Node.js backend, Python service, or Go worker, the request fails with a &lt;code&gt;400 Bad Request&lt;/code&gt;, a &lt;code&gt;403 Forbidden&lt;/code&gt;, or silent payload corruption.&lt;/p&gt;

&lt;p&gt;Translating raw cURL commands into idiomatic production code seems straightforward, but subtle differences in HTTP protocol handling, shell escaping, and client library defaults introduce tricky edge cases. Here are five common pitfalls to watch out for when converting cURL commands to code.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. HTTP/2 Pseudo-Headers (&lt;code&gt;:authority:&lt;/code&gt;, &lt;code&gt;:path:&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;When you right-click a network request in browser DevTools and select &lt;strong&gt;Copy as cURL&lt;/strong&gt;, the browser exports exact HTTP headers—including HTTP/2 pseudo-headers like &lt;code&gt;:authority:&lt;/code&gt;, &lt;code&gt;:method:&lt;/code&gt;, &lt;code&gt;:path:&lt;/code&gt;, and &lt;code&gt;:scheme:&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s1"&gt;'https://api.example.com/v1/data'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;':authority: api.example.com'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;':path: /v1/data'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'user-agent: Mozilla/5.0...'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you copy these headers directly into a Python &lt;code&gt;requests&lt;/code&gt; call or a Node.js &lt;code&gt;fetch()&lt;/code&gt; header object, HTTP/1.1 clients will either throw an invalid header error or send colons in HTTP header names, causing upstream servers to reject the request. Always strip leading colons from header names when migrating from browser cURL dumps to backend code.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Body Payloads: &lt;code&gt;-d&lt;/code&gt; vs &lt;code&gt;--data-raw&lt;/code&gt; vs &lt;code&gt;--data-binary&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;cURL supports multiple flags for request bodies, each with distinct parsing behavior:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-d&lt;/code&gt; or &lt;code&gt;--data&lt;/code&gt;: Strips carriage returns and newlines from input files.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--data-raw&lt;/code&gt;: Passes string data directly without inspecting &lt;code&gt;@&lt;/code&gt; symbols for file uploads.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--data-binary&lt;/code&gt;: Preserves exact bytes, including line breaks and binary data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Consider a GraphQL payload sent via cURL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s1"&gt;'https://api.example.com/graphql'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data-raw&lt;/span&gt; &lt;span class="s1"&gt;'{"query":"query { user { id name } }"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your code implementation assumes standard JSON parsing without escaping quote characters or handling multi-line strings, the JSON payload will fail schema validation.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Compression Headers (&lt;code&gt;Accept-Encoding: gzip, deflate, br&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Browser-generated cURL commands include &lt;code&gt;Accept-Encoding: gzip, deflate, br&lt;/code&gt;. Terminal &lt;code&gt;curl&lt;/code&gt; automatically ignores response decompression unless you pass &lt;code&gt;--compressed&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;However, in custom HTTP implementations (such as Go's &lt;code&gt;net/http&lt;/code&gt; or raw socket clients), explicitly setting &lt;code&gt;Accept-Encoding: gzip&lt;/code&gt; disables automatic response body decompression in some libraries. As a result, &lt;code&gt;response.text()&lt;/code&gt; returns gzipped binary garbage instead of expected text or JSON. Unless your client library handles decompression explicitly, omit &lt;code&gt;Accept-Encoding&lt;/code&gt; when converting cURL calls.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. Shell Quoting and Escape Sequences
&lt;/h3&gt;

&lt;p&gt;Bash and Zsh handle single quotes (&lt;code&gt;'&lt;/code&gt;) by preserving literal text, while Windows Command Prompt (&lt;code&gt;cmd.exe&lt;/code&gt;) does not recognize single quotes as string delimiters.&lt;/p&gt;

&lt;p&gt;If a developer on macOS shares this cURL snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://api.example.com/items &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"name": "Dev O'''&lt;/span&gt;Neill&lt;span class="s2"&gt;"}'
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pasting this into Windows &lt;code&gt;cmd&lt;/code&gt; or raw Python string templates will break string boundaries due to single-quote escaping (&lt;code&gt;'\''&lt;/code&gt;). When converting cURL snippets for cross-platform team documentation, standardize on JSON objects rather than shell-escaped raw strings.&lt;/p&gt;




&lt;h3&gt;
  
  
  5. Raw Cookie Strings vs Session State
&lt;/h3&gt;

&lt;p&gt;DevTools exports cookies as a single raw header: &lt;code&gt;-H 'cookie: session_id=xyz123; theme=dark'&lt;/code&gt;. Passing a raw cookie string in your application code bypasses built-in cookie jar management, CORS credential flags, and automatic session renewal in HTTP client SDKs.&lt;/p&gt;




&lt;h3&gt;
  
  
  Streamlining cURL Conversion
&lt;/h3&gt;

&lt;p&gt;When refactoring complex cURL commands with multi-line headers, OAuth tokens, and nested payloads, manual translation is error-prone. Using a client-side utility like &lt;a href="https://nutilz.com/curl-to-code" rel="noopener noreferrer"&gt;Nutilz cURL to Code&lt;/a&gt; allows you to instantly generate clean Python &lt;code&gt;requests&lt;/code&gt;, JavaScript &lt;code&gt;fetch()&lt;/code&gt;, or Go &lt;code&gt;http.NewRequest&lt;/code&gt; snippets. Because processing happens entirely in the browser, sensitive API keys and tokens never leave your machine.&lt;/p&gt;




&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Automating API requests from terminal prototypes to production code requires attention to header sanitization, payload encoding, and compression defaults. By auditing pseudo-headers and payload flags before committing code, you eliminate silent request failures. For fast, zero-data-leak conversions during API integration, bookmark &lt;a href="https://nutilz.com/curl-to-code" rel="noopener noreferrer"&gt;nutilz.com/curl-to-code&lt;/a&gt; alongside your daily developer toolkit.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>python</category>
      <category>programming</category>
    </item>
    <item>
      <title>Why Linux Permission Bugs Cause Security Incidents (And the Chmod Math Edge Cases Every Developer Misses)</title>
      <dc:creator>Rasika Dangamuwa</dc:creator>
      <pubDate>Sun, 09 Aug 2026 21:00:58 +0000</pubDate>
      <link>https://dev.to/rasika_dangamuwa_ed1074fe/why-linux-permission-bugs-cause-security-incidents-and-the-chmod-math-edge-cases-every-developer-3342</link>
      <guid>https://dev.to/rasika_dangamuwa_ed1074fe/why-linux-permission-bugs-cause-security-incidents-and-the-chmod-math-edge-cases-every-developer-3342</guid>
      <description>&lt;p&gt;Every developer has encountered it: a deployment pipeline fails with &lt;code&gt;Permissions 0644 for '/root/.ssh/id_rsa' are too open&lt;/code&gt;, an Nginx container returns &lt;code&gt;403 Forbidden&lt;/code&gt; on static assets, or a script executing in CI throws &lt;code&gt;Permission denied&lt;/code&gt;. The instant reaction is often to run &lt;code&gt;chmod 777&lt;/code&gt; to "fix it quickly," introducing critical security vulnerabilities into production environments.&lt;/p&gt;

&lt;p&gt;Understanding POSIX file permissions, octal bitmask calculations, and how Linux permission inheritance actually works is essential for modern backend, DevOps, and cloud engineering.&lt;/p&gt;

&lt;h3&gt;
  
  
  How the Chmod Bitmask Math Works
&lt;/h3&gt;

&lt;p&gt;Linux file permissions rely on a 9-bit matrix divided into three scopes: &lt;strong&gt;Owner (User)&lt;/strong&gt;, &lt;strong&gt;Group&lt;/strong&gt;, and &lt;strong&gt;Others (World)&lt;/strong&gt;. Each scope contains three permission bits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Read (r)&lt;/strong&gt; = 4 (binary &lt;code&gt;100&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write (w)&lt;/strong&gt; = 2 (binary &lt;code&gt;010&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execute (x)&lt;/strong&gt; = 1 (binary &lt;code&gt;001&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The numeric permission for each scope is calculated by summing the active bit values. For example, &lt;code&gt;Read (4) + Write (2) = 6&lt;/code&gt; (&lt;code&gt;rw-&lt;/code&gt;), while &lt;code&gt;Read (4) + Execute (1) = 5&lt;/code&gt; (&lt;code&gt;r-x&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Combining these three scopes yields the standard 3-digit octal notation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;755&lt;/code&gt;&lt;/strong&gt; (&lt;code&gt;rwxr-xr-x&lt;/code&gt;): Full access for owner (&lt;code&gt;4+2+1=7&lt;/code&gt;); read and execute for group and others (&lt;code&gt;4+1=5&lt;/code&gt;). Standard for executables, binaries, and directories.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;644&lt;/code&gt;&lt;/strong&gt; (&lt;code&gt;rw-r--r--&lt;/code&gt;): Read and write for owner (&lt;code&gt;4+2=6&lt;/code&gt;); read-only for group and others (&lt;code&gt;4+0+0=4&lt;/code&gt;). Standard for static files, HTML, and configuration files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;600&lt;/code&gt;&lt;/strong&gt; (&lt;code&gt;rw-------&lt;/code&gt;): Read and write for owner only (&lt;code&gt;4+2=6&lt;/code&gt;); zero access for everyone else. Mandatory for SSH private keys (&lt;code&gt;id_rsa&lt;/code&gt;), database credentials, and &lt;code&gt;.env&lt;/code&gt; files.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4 Common Linux Permission Pitfalls in Production
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Directory Execution vs. File Execution
&lt;/h4&gt;

&lt;p&gt;In POSIX file systems, the &lt;code&gt;Execute (x)&lt;/code&gt; bit means entirely different things for files and directories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For a &lt;strong&gt;file&lt;/strong&gt;, &lt;code&gt;x&lt;/code&gt; allows running it as a binary or shell script.&lt;/li&gt;
&lt;li&gt;For a &lt;strong&gt;directory&lt;/strong&gt;, &lt;code&gt;x&lt;/code&gt; allows entering (traversing) it with &lt;code&gt;cd&lt;/code&gt; or accessing files inside it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a web server directory is set to &lt;code&gt;644&lt;/code&gt; (&lt;code&gt;rw-r--r--&lt;/code&gt;), Nginx or Apache will fail to serve files inside it with a &lt;code&gt;403 Forbidden&lt;/code&gt; error because the web server worker process lacks directory traversal privileges (&lt;code&gt;x&lt;/code&gt;). Directories must always be &lt;code&gt;755&lt;/code&gt; or &lt;code&gt;750&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. The Umask Masking Calculation
&lt;/h4&gt;

&lt;p&gt;When a process creates a file or directory, default permissions are determined by subtracting the system &lt;code&gt;umask&lt;/code&gt; from maximum base permissions (&lt;code&gt;666&lt;/code&gt; for files, &lt;code&gt;777&lt;/code&gt; for directories):&lt;/p&gt;

&lt;p&gt;With a default &lt;code&gt;umask 022&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;New files get &lt;code&gt;666 - 022 = 644&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;New directories get &lt;code&gt;777 - 022 = 755&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a CI script generates build artifacts under &lt;code&gt;umask 027&lt;/code&gt;, group members lose write permissions (&lt;code&gt;640&lt;/code&gt;), and world users lose all access.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Special Permission Bits: SUID, SGID, and Sticky Bit
&lt;/h4&gt;

&lt;p&gt;A 4-digit chmod octal string includes a leading special mode digit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SUID (&lt;code&gt;4000&lt;/code&gt;)&lt;/strong&gt;: Executes the file with owner privileges (e.g., &lt;code&gt;chmod 4755 /usr/bin/passwd&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SGID (&lt;code&gt;2000&lt;/code&gt;)&lt;/strong&gt;: Inherits directory group ownership for newly created files within that directory (&lt;code&gt;chmod 2775 /shared&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sticky Bit (&lt;code&gt;1000&lt;/code&gt;)&lt;/strong&gt;: Prevents users from deleting or renaming files owned by others in a shared directory (&lt;code&gt;chmod 1777 /tmp&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Accidentally applying SUID (&lt;code&gt;chmod 4777&lt;/code&gt;) to custom scripts allows unprivileged local users to achieve instant root privilege escalation.&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Docker Volume Permission Mismatches
&lt;/h4&gt;

&lt;p&gt;When mounting host volumes into Docker containers (&lt;code&gt;-v /host/path:/container/path&lt;/code&gt;), Linux evaluates numeric UIDs/GIDs rather than usernames. If host files are owned by UID &lt;code&gt;1000&lt;/code&gt; (&lt;code&gt;ubuntu&lt;/code&gt;), but the container runs as non-root UID &lt;code&gt;1001&lt;/code&gt; (&lt;code&gt;node&lt;/code&gt;), the app will fail with &lt;code&gt;EACCES: permission denied&lt;/code&gt; unless permissions are adjusted to allow group write access (&lt;code&gt;664&lt;/code&gt; or &lt;code&gt;775&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;When configuring complex server deployments, testing octal combinations against symbolic representations (&lt;code&gt;rwxr-xr-x&lt;/code&gt;) avoids misconfigurations. Tools like the &lt;a href="https://nutilz.com/chmod-calculator" rel="noopener noreferrer"&gt;Nutilz Chmod Calculator&lt;/a&gt; help visually toggle permissions for User, Group, and Others to verify octal values and generate valid command strings before pushing to production servers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Best Practices for Secure Permissions
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Principle of Least Privilege&lt;/strong&gt;: Never use &lt;code&gt;777&lt;/code&gt;. Use &lt;code&gt;600&lt;/code&gt; for secrets, &lt;code&gt;644&lt;/code&gt; for web assets, and &lt;code&gt;755&lt;/code&gt; for directories.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audit Open Files&lt;/strong&gt;: Periodically inspect world-writable files across server environments:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   find /var/www &lt;span class="nt"&gt;-type&lt;/span&gt; f &lt;span class="nt"&gt;-perm&lt;/span&gt; &lt;span class="nt"&gt;-0002&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Use Presets in Deployment Automation&lt;/strong&gt;: Hardcode permission masks in Ansible, Dockerfiles, or Terraform scripts rather than running ad-hoc chmod invocations.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Using structured permission auditing and tools such as &lt;a href="https://nutilz.com/chmod-calculator" rel="noopener noreferrer"&gt;nutilz.com/chmod-calculator&lt;/a&gt; ensures your infrastructure stays secure without breaking deployment workflows.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>devops</category>
      <category>security</category>
      <category>webdev</category>
    </item>
    <item>
      <title>JSON to Protobuf Schema Conversion: Type Ambiguity, Field Tags, and Proto3 Pitfalls</title>
      <dc:creator>Rasika Dangamuwa</dc:creator>
      <pubDate>Sun, 09 Aug 2026 19:00:45 +0000</pubDate>
      <link>https://dev.to/rasika_dangamuwa_ed1074fe/json-to-protobuf-schema-conversion-type-ambiguity-field-tags-and-proto3-pitfalls-3hhe</link>
      <guid>https://dev.to/rasika_dangamuwa_ed1074fe/json-to-protobuf-schema-conversion-type-ambiguity-field-tags-and-proto3-pitfalls-3hhe</guid>
      <description>&lt;p&gt;When migrating microservices from REST APIs to gRPC, converting existing JSON payloads into Protocol Buffers (&lt;code&gt;.proto&lt;/code&gt;) schemas is one of the first hurdles backend engineers encounter. While JSON is schema-less, human-readable, and flexible, Protobuf relies on strict, strongly-typed schemas with field tag numbers to maximize binary serialization performance.&lt;/p&gt;

&lt;p&gt;Translating a nested JSON object into a &lt;code&gt;proto3&lt;/code&gt; message definition seems straightforward at first glance, but several subtle edge cases can introduce breaking changes, runtime bugs, or unexpected wire size inflation if handled naively.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The Number Dilemma: Double vs. Int64 vs. Sint32
&lt;/h3&gt;

&lt;p&gt;In JSON specification (RFC 8259), all numbers are represented identically without distinguishing between integers and floating-point values. JavaScript engines treat all JSON numbers as IEEE 754 double-precision floats.&lt;/p&gt;

&lt;p&gt;In Protobuf, however, numeric type selection directly impacts wire encoding and memory layout:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Standard integers (&lt;code&gt;int32&lt;/code&gt;, &lt;code&gt;int64&lt;/code&gt;) use varint encoding, which compresses small positive values to 1 or 2 bytes.&lt;/li&gt;
&lt;li&gt;Negative numbers with &lt;code&gt;int32&lt;/code&gt;/&lt;code&gt;int64&lt;/code&gt; use a full 10 bytes on the wire. If your domain includes negative integers (like temperature or financial deltas), you must explicitly use &lt;code&gt;sint32&lt;/code&gt; or &lt;code&gt;sint64&lt;/code&gt; (ZigZag encoding) to keep payloads lightweight.&lt;/li&gt;
&lt;li&gt;High-precision IDs exceeding &lt;code&gt;2^53 - 1&lt;/code&gt; (like 64-bit database keys or Snowflake IDs) will suffer floating-point truncation when parsed in JavaScript JSON objects unless serialized as strings.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Consider this raw JSON 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;"user_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;9007199254740993&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"account_balance"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1450.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;"score_delta"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"login_count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;42&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;Inferring the schema requires assigning appropriate types rather than defaulting every number to &lt;code&gt;double&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight protobuf"&gt;&lt;code&gt;&lt;span class="na"&gt;syntax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"proto3"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;UserStats&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;int64&lt;/span&gt; &lt;span class="na"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="na"&gt;account_balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;sint32&lt;/span&gt; &lt;span class="na"&gt;score_delta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;int32&lt;/span&gt; &lt;span class="na"&gt;login_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&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;h3&gt;
  
  
  2. Timestamps and Date Formatting
&lt;/h3&gt;

&lt;p&gt;JSON APIs typically pass dates as ISO 8601 strings (e.g., &lt;code&gt;"2026-08-09T19:00:00Z"&lt;/code&gt;). While you can map these to &lt;code&gt;string&lt;/code&gt; in Protobuf, doing so forces downstream consumers to parse date strings repeatedly in hot paths.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;proto3&lt;/code&gt;, standard practice dictates importing &lt;code&gt;google/protobuf/timestamp.proto&lt;/code&gt; and mapping string dates to &lt;code&gt;google.protobuf.Timestamp&lt;/code&gt;. This structures timestamps as Unix epoch seconds and nanoseconds, ensuring fast, timezone-agnostic comparison operations across microservices.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Null Values and Zero-Value Serialization
&lt;/h3&gt;

&lt;p&gt;One of the most dangerous surprises in &lt;code&gt;proto3&lt;/code&gt; is default value elision. In proto3, scalar fields with default values (0 for integers, &lt;code&gt;""&lt;/code&gt; for strings, &lt;code&gt;false&lt;/code&gt; for booleans) are not written to the binary stream.&lt;/p&gt;

&lt;p&gt;When deserializing a JSON object like &lt;code&gt;{"item_count": 0, "status": ""}&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A JSON consumer explicitly sees &lt;code&gt;item_count&lt;/code&gt; with value &lt;code&gt;0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A Protobuf consumer receives an empty byte array and sets &lt;code&gt;item_count&lt;/code&gt; to its default (&lt;code&gt;0&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your application logic needs to differentiate between "field present with value 0" and "field omitted/unset", you must wrap the scalar in &lt;code&gt;google.protobuf.Int32Value&lt;/code&gt; or use the &lt;code&gt;optional&lt;/code&gt; field presence modifier supported in modern protoc compilers.&lt;/p&gt;

&lt;p&gt;When bootstrapping schemas from large JSON responses, utilizing an interactive converter like &lt;a href="https://nutilz.com/json-to-protobuf" rel="noopener noreferrer"&gt;Nutilz JSON to Protobuf&lt;/a&gt; helps visualize how nested JSON structures convert into sub-messages, repeated fields, and proto3 types in real time.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Field Tags and Encoding Efficiency
&lt;/h3&gt;

&lt;p&gt;Protobuf does not send field names over the network; it sends integer field tags (e.g., &lt;code&gt;1&lt;/code&gt;, &lt;code&gt;2&lt;/code&gt;, &lt;code&gt;3&lt;/code&gt;).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tags &lt;code&gt;1&lt;/code&gt; through &lt;code&gt;15&lt;/code&gt; take &lt;strong&gt;1 byte&lt;/strong&gt; to encode both the field tag and wire type.&lt;/li&gt;
&lt;li&gt;Tags &lt;code&gt;16&lt;/code&gt; through &lt;code&gt;2047&lt;/code&gt; take &lt;strong&gt;2 bytes&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When mapping high-frequency JSON payload fields, assign tags &lt;code&gt;1&lt;/code&gt; through &lt;code&gt;15&lt;/code&gt; to the most commonly accessed or largest payload attributes to minimize serialization overhead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;Converting JSON to Protobuf is more than a simple syntax translation. It requires deliberate decisions regarding scalar types, varint efficiency, default elision, and timestamp standards. Tools like &lt;a href="https://nutilz.com/json-to-protobuf" rel="noopener noreferrer"&gt;Nutilz&lt;/a&gt; streamline the initial schema creation, but reviewing scalar types and field tag assignments remains essential for robust production gRPC APIs.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Cron Syntax Edge Cases That Break Production Jobs: DST, Field Misalignment, and the Day-of-Month Trap</title>
      <dc:creator>Rasika Dangamuwa</dc:creator>
      <pubDate>Sun, 09 Aug 2026 13:01:40 +0000</pubDate>
      <link>https://dev.to/rasika_dangamuwa_ed1074fe/cron-syntax-edge-cases-that-break-production-jobs-dst-field-misalignment-and-the-day-of-month-4jc3</link>
      <guid>https://dev.to/rasika_dangamuwa_ed1074fe/cron-syntax-edge-cases-that-break-production-jobs-dst-field-misalignment-and-the-day-of-month-4jc3</guid>
      <description>&lt;p&gt;Cron expressions are the invisible backbone of backend infrastructure. From nightly database backups and cache warmups to recurring billing cycles, developers rely on cron syntax to run scheduled tasks across servers and cloud functions.&lt;/p&gt;

&lt;p&gt;Because the syntax looks simple on the surface—five space-separated fields representing minutes, hours, day of month, month, and day of week—it is easy to assume that any valid-looking cron string will execute exactly as expected. In production, however, subtle parser differences, timezone shifts, and unexpected field interaction rules regularly cause jobs to run twice, run at the wrong time, or skip execution entirely.&lt;/p&gt;

&lt;p&gt;Here are the three most common cron syntax edge cases that cause production incidents, and how to avoid them.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The Day-of-Month and Day-of-Week "OR" Logic Trap
&lt;/h3&gt;

&lt;p&gt;The single most frequent mistake when writing cron schedules is combining &lt;code&gt;Day of Month&lt;/code&gt; (field 3) and &lt;code&gt;Day of Week&lt;/code&gt; (field 5).&lt;/p&gt;

&lt;p&gt;Intuition tells us that &lt;code&gt;0 0 15 * 5&lt;/code&gt; should mean &lt;em&gt;"run at midnight on Friday the 15th"&lt;/em&gt;. Standard Vixie Cron and POSIX specifications, however, define a special rule: if &lt;strong&gt;both&lt;/strong&gt; day-of-month and day-of-week are specified (i.e. neither is &lt;code&gt;*&lt;/code&gt;), the fields are evaluated as an &lt;strong&gt;OR&lt;/strong&gt; condition, not an &lt;strong&gt;AND&lt;/strong&gt; condition.&lt;/p&gt;

&lt;p&gt;As a result, &lt;code&gt;0 0 15 * 5&lt;/code&gt; actually means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run at midnight on the 15th of every month, &lt;strong&gt;AND&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Run at midnight on every Friday of every month.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your intention was to target only Fridays that land on the 15th, your job will end up running 5 to 6 times per month instead of once or twice a year. To implement true "AND" logic, you must schedule the job to run every Friday (&lt;code&gt;0 0 * * 5&lt;/code&gt;) and check the calendar date inside your script execution code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Bash example checking if today is the 15th&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +%d&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-ne&lt;/span&gt; 15 &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;exit &lt;/span&gt;0
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Daylight Saving Time (DST) Transitions
&lt;/h3&gt;

&lt;p&gt;If your server or process scheduler runs in a local timezone (such as &lt;code&gt;America/New_York&lt;/code&gt; or &lt;code&gt;Europe/London&lt;/code&gt;), biannual Daylight Saving Time adjustments introduce two distinct failure modes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Spring Forward (Lost Hour):&lt;/strong&gt; When the clock jumps from &lt;code&gt;01:59:59&lt;/code&gt; directly to &lt;code&gt;03:00:00&lt;/code&gt;, any job scheduled between &lt;code&gt;02:00&lt;/code&gt; and &lt;code&gt;02:59&lt;/code&gt; (for instance &lt;code&gt;30 2 * * *&lt;/code&gt;) is skipped because that time range never occurs on the clock.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fall Back (Repeated Hour):&lt;/strong&gt; When the clock moves backward from &lt;code&gt;02:00:00&lt;/code&gt; to &lt;code&gt;01:00:00&lt;/code&gt;, jobs scheduled between &lt;code&gt;01:00&lt;/code&gt; and &lt;code&gt;01:59&lt;/code&gt; fire twice unless your runner tracks execution state idempotently in a database.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The standard industry fix is to run all cron daemons in &lt;strong&gt;UTC&lt;/strong&gt;. If business requirements dictate local time schedules, use explicit systemd timers with calendar specifications or a scheduler engine that handles timezone offsets natively.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Field Misalignment (5-Field vs 6-Field Syntax)
&lt;/h3&gt;

&lt;p&gt;Standard UNIX crontab uses 5 fields:&lt;br&gt;
&lt;code&gt;[minute] [hour] [day-of-month] [month] [day-of-week]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;However, popular libraries and cloud platforms use non-standard extensions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Quartz Scheduler / AWS EventBridge:&lt;/strong&gt; 6 or 7 fields, requiring a &lt;code&gt;seconds&lt;/code&gt; field at position 0 or a &lt;code&gt;year&lt;/code&gt; field at the end.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Node-cron:&lt;/strong&gt; Optional 6th field for seconds (&lt;code&gt;seconds minute hour dom month dow&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a developer pastes a 6-field string like &lt;code&gt;0 30 2 * * *&lt;/code&gt; into a standard 5-field parser, the parser evaluates &lt;code&gt;0&lt;/code&gt; as minute, &lt;code&gt;30&lt;/code&gt; as hour, and &lt;code&gt;2&lt;/code&gt; as day-of-month! Suddenly, a job intended to run daily at 2:30 AM is re-interpreted to run at 30:00 (invalid) or at 00:30 on the 2nd of every month.&lt;/p&gt;

&lt;p&gt;When inspecting or debugging complex schedules across microservices, using an interactive tool like the &lt;a href="https://nutilz.com/cron-parser" rel="noopener noreferrer"&gt;Nutilz Cron Parser&lt;/a&gt; helps quickly verify human-readable schedule explanations and inspect upcoming execution timestamps in both UTC and local time without needing to run local node scripts or crontab checks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Best Practices for Production Cron Jobs
&lt;/h3&gt;

&lt;p&gt;To ensure your scheduled tasks are reliable and predictable:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Always use UTC&lt;/strong&gt; for server environments and schedule definitions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make jobs idempotent:&lt;/strong&gt; A job should produce identical results if executed multiple times in the event of DST fall-backs or retry loops.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate schedule syntax:&lt;/strong&gt; Before committing crontab changes or Kubernetes CronJob manifests, test your expressions against a parser like &lt;a href="https://nutilz.com/cron-parser" rel="noopener noreferrer"&gt;Nutilz Cron Parser&lt;/a&gt; to catch field offset issues early.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By understanding how parsers interpret day fields, timezone shifts, and non-standard syntax, you can prevent quiet job failures before they reach production.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>programming</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Why Base64 Decoding a JWT Isn't Enough: 5 Security Edge Cases Every Developer Misses</title>
      <dc:creator>Rasika Dangamuwa</dc:creator>
      <pubDate>Sat, 08 Aug 2026 00:23:34 +0000</pubDate>
      <link>https://dev.to/rasika_dangamuwa_ed1074fe/why-base64-decoding-a-jwt-isnt-enough-5-security-edge-cases-every-developer-misses-10fm</link>
      <guid>https://dev.to/rasika_dangamuwa_ed1074fe/why-base64-decoding-a-jwt-isnt-enough-5-security-edge-cases-every-developer-misses-10fm</guid>
      <description>&lt;p&gt;In modern microservice architectures and single-page applications, JSON Web Tokens (JWTs) are the de facto standard for stateless authorization. Because a JWT looks like a simple dot-separated string containing Base64-encoded JSON, developers frequently write quick inline decoders or naive middleware to extract user IDs, scopes, or expiration timestamps.&lt;/p&gt;

&lt;p&gt;That simplicity is deceptive. Inspecting claims without understanding the underlying RFC 7519 spec and cryptographic edge cases leads to silent authentication failures, clock drift bugs, or severe authorization bypass vulnerabilities. Here are 5 critical edge cases every developer should know when working with JWTs.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Base64 vs. Base64URL Encoding &amp;amp; Missing Padding
&lt;/h3&gt;

&lt;p&gt;JWTs do not use standard Base64 (&lt;code&gt;RFC 4648 §4&lt;/code&gt;); they use Base64URL (&lt;code&gt;RFC 4648 §5&lt;/code&gt;). Standard Base64 uses &lt;code&gt;+&lt;/code&gt; and &lt;code&gt;/&lt;/code&gt; characters and relies on &lt;code&gt;=&lt;/code&gt; padding bytes. Base64URL replaces &lt;code&gt;+&lt;/code&gt; with &lt;code&gt;-&lt;/code&gt; and &lt;code&gt;/&lt;/code&gt; with &lt;code&gt;_&lt;/code&gt;, and explicitly omits trailing &lt;code&gt;=&lt;/code&gt; padding.&lt;/p&gt;

&lt;p&gt;If your custom decoder uses standard &lt;code&gt;atob()&lt;/code&gt; or &lt;code&gt;Buffer.from(str, 'base64')&lt;/code&gt; without sanitizing input:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Strings with length not divisible by 4 will fail or throw &lt;code&gt;Invalid Character&lt;/code&gt; errors.&lt;/li&gt;
&lt;li&gt;Characters like &lt;code&gt;-&lt;/code&gt; or &lt;code&gt;_&lt;/code&gt; will corrupt the decoded JSON string.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To safely decode Base64URL in JavaScript:&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;decodeBase64URL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;base64&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/-/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;+&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/_/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;base64&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;=&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;return&lt;/span&gt; &lt;span class="nf"&gt;atob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;base64&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;h3&gt;
  
  
  2. The &lt;code&gt;alg: "none"&lt;/code&gt; Signature Bypass
&lt;/h3&gt;

&lt;p&gt;A JWT header contains metadata specifying how the token was created:&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;"alg"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"none"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"typ"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"JWT"&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;RFC 7519 allows an algorithm of &lt;code&gt;"none"&lt;/code&gt; for unsigned tokens. In early implementations of popular JWT libraries, attackers could take a valid token, modify the payload (e.g., changing &lt;code&gt;"role": "user"&lt;/code&gt; to &lt;code&gt;"role": "admin"&lt;/code&gt;), change &lt;code&gt;alg&lt;/code&gt; to &lt;code&gt;"none"&lt;/code&gt;, and strip the signature portion entirely. Naive verification functions that trusted the header's &lt;code&gt;alg&lt;/code&gt; parameter would skip signature verification and accept the token as valid.&lt;/p&gt;

&lt;p&gt;Server-side verification logic must &lt;strong&gt;never&lt;/strong&gt; trust the algorithm defined inside the incoming token header. Always specify an explicit whitelist of allowed algorithms in your verification options: &lt;code&gt;jwt.verify(token, secret, { algorithms: ['HS256'] })&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Timestamp Units &amp;amp; Clock Skew
&lt;/h3&gt;

&lt;p&gt;Standard claims like &lt;code&gt;exp&lt;/code&gt; (expiration), &lt;code&gt;iat&lt;/code&gt; (issued at), and &lt;code&gt;nbf&lt;/code&gt; (not before) are defined as &lt;code&gt;NumericDate&lt;/code&gt; values — Unix timestamps in &lt;strong&gt;seconds&lt;/strong&gt; since January 1, 1970 UTC.&lt;/p&gt;

&lt;p&gt;A common bug occurs when developers compare &lt;code&gt;payload.exp&lt;/code&gt; against JavaScript's &lt;code&gt;Date.now()&lt;/code&gt;, which returns &lt;strong&gt;milliseconds&lt;/strong&gt;:&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="c1"&gt;// BUG: exp is in seconds (e.g. 1700000000), Date.now() is in ms (1700000000000)&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exp&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Token appears expired 50 years into the future!&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Always convert &lt;code&gt;Date.now()&lt;/code&gt; to seconds (&lt;code&gt;Math.floor(Date.now() / 1000)&lt;/code&gt;) before comparing.&lt;/p&gt;

&lt;p&gt;Additionally, distributed servers suffer from minor clock drift. If an auth server issues a token at &lt;code&gt;12:00:05&lt;/code&gt; and sends it to an API server whose system clock is set to &lt;code&gt;12:00:00&lt;/code&gt;, the API server will reject the token because &lt;code&gt;nbf&lt;/code&gt; or &lt;code&gt;iat&lt;/code&gt; is in the future. Always configure a clock tolerance (e.g. 5 seconds) in your JWT verification middleware.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Algorithm Confusion (RS256 vs. HS256)
&lt;/h3&gt;

&lt;p&gt;When an authentication server uses RS256 (asymmetric RSA signature), it signs tokens with a private key and publishes a public key for API services to verify signatures.&lt;/p&gt;

&lt;p&gt;If the verification middleware accepts whatever algorithm is declared in the token header, an attacker can exploit algorithm confusion:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The attacker obtains the public key (which is publicly accessible).&lt;/li&gt;
&lt;li&gt;The attacker crafts a forged payload and changes the header algorithm to &lt;code&gt;HS256&lt;/code&gt; (symmetric HMAC).&lt;/li&gt;
&lt;li&gt;The attacker signs the token using the public RSA key as the HMAC secret string!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Because &lt;code&gt;HS256&lt;/code&gt; uses a shared secret, when the server calls &lt;code&gt;jwt.verify(token, publicKey)&lt;/code&gt;, the library sees &lt;code&gt;alg: HS256&lt;/code&gt; in the header, uses &lt;code&gt;publicKey&lt;/code&gt; as a raw secret, and verifies the signature successfully.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Non-Standard Claims and Type Mismatches
&lt;/h3&gt;

&lt;p&gt;RFC 7519 allows claims like &lt;code&gt;aud&lt;/code&gt; (audience) to be either a single string or an array of strings:&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;"aud"&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;"https://api.example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://billing.example.com"&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;If your validation code assumes &lt;code&gt;typeof payload.aud === 'string'&lt;/code&gt;, inspecting complex tokens will throw unhandled runtime exceptions.&lt;/p&gt;

&lt;p&gt;When inspecting token payloads during local API integration or debugging authorization header issues, manually splitting tokens and decoding Base64 strings in terminal commands can be error-prone. Using a dedicated browser-based utility like the &lt;a href="https://nutilz.com/jwt-decoder" rel="noopener noreferrer"&gt;Nutilz JWT Decoder&lt;/a&gt; allows you to instantly inspect header parameters, claims, and expiration timestamps locally without exposing sensitive production keys or sending network calls.&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;Stateless tokens eliminate database lookups for session management, but their security depends entirely on proper parsing and strict validation. Never trust the &lt;code&gt;alg&lt;/code&gt; header parameter, handle Base64URL padding quirks explicitly, normalize Unix timestamps to seconds, and guard against algorithm confusion attacks. For quick visual inspection of payloads and claims during development, use the &lt;a href="https://nutilz.com/jwt-decoder" rel="noopener noreferrer"&gt;Nutilz JWT Decoder&lt;/a&gt; to debug tokens safely in your browser.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>security</category>
      <category>programming</category>
    </item>
    <item>
      <title>Why Your PWA Isn't Installable: The manifest.json Pitfalls That Silent-Fail in Production</title>
      <dc:creator>Rasika Dangamuwa</dc:creator>
      <pubDate>Fri, 07 Aug 2026 13:01:27 +0000</pubDate>
      <link>https://dev.to/rasika_dangamuwa_ed1074fe/why-your-pwa-isnt-installable-the-manifestjson-pitfalls-that-silent-fail-in-production-4bk4</link>
      <guid>https://dev.to/rasika_dangamuwa_ed1074fe/why-your-pwa-isnt-installable-the-manifestjson-pitfalls-that-silent-fail-in-production-4bk4</guid>
      <description>&lt;p&gt;Building a Progressive Web App (PWA) seems straightforward on paper: write your web application, register a Service Worker, serve over HTTPS, and drop a &lt;code&gt;manifest.json&lt;/code&gt; file into your root directory. Yet developers frequently discover that Chrome, Safari, or Edge refuses to trigger the install prompt, displays broken splash screens, or fails Lighthouse audits without clear error messages.&lt;/p&gt;

&lt;p&gt;The culprit is almost always subtle misconfigurations inside &lt;code&gt;manifest.json&lt;/code&gt;. Modern web browser engines strictly validate web application manifests before granting installation privileges or custom display frames. Here is a breakdown of why PWA manifests silently fail in production, how browsers process manifest metadata, and how to structure your manifest properly.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. The Icon Matrix and Maskable Icons
&lt;/h3&gt;

&lt;p&gt;The single most common reason Chromium-based browsers refuse to offer an install prompt is an incomplete &lt;code&gt;icons&lt;/code&gt; array. Browsers require specific pixel dimensions and icon formats to render home screen icons, app switchers, and splash screens across high-DPI devices.&lt;/p&gt;

&lt;p&gt;At a minimum, your manifest must include 192x192 and 512x512 PNG images. However, Android OS uses maskable icons (adaptive icons with safe zones) to prevent arbitrary cropping. If you provide standard transparent PNGs without specifying icon purpose, Android will wrap your icon in an unsightly white circle or square.&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;"icons"&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;"src"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/icons/icon-192x192.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"sizes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"192x192"&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;"image/png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"purpose"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"any"&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;"src"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/icons/icon-512x512.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"sizes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"512x512"&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;"image/png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"purpose"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"maskable"&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;If your server responds with an incorrect &lt;code&gt;Content-Type&lt;/code&gt; header for icon assets (e.g., serving PNGs as &lt;code&gt;text/plain&lt;/code&gt;) or returns a 404 due to relative path resolution issues, the browser silently invalidates the entire install candidate.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Scope vs. Start URL Mismatches
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;start_url&lt;/code&gt; property tells the device where to launch the application when tapped from the home screen, while &lt;code&gt;scope&lt;/code&gt; defines the URL navigation boundary for the standalone window.&lt;/p&gt;

&lt;p&gt;A classic mistake occurs when &lt;code&gt;start_url&lt;/code&gt; points outside the defined &lt;code&gt;scope&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;"scope"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/app/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"start_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/index.html"&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;Because &lt;code&gt;/index.html&lt;/code&gt; falls outside &lt;code&gt;/app/&lt;/code&gt;, Chromium treats the manifest as invalid for PWA installation. Always ensure &lt;code&gt;start_url&lt;/code&gt; is relative to or contained within &lt;code&gt;scope&lt;/code&gt;. Using query parameters like &lt;code&gt;"start_url": "/?utm_source=pwa"&lt;/code&gt; is standard practice for analytics tracking, provided the base path matches the scope.&lt;/p&gt;

&lt;p&gt;If you want to avoid syntax typos or scope path errors while drafting your manifest, you can quickly generate a fully spec-compliant JSON file using the free &lt;a href="https://nutilz.com/pwa-manifest-generator" rel="noopener noreferrer"&gt;PWA Manifest Generator on Nutilz&lt;/a&gt;, which formats icons, theme colors, and display scopes in your browser.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Display Modes and Theme Color Bleed
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;display&lt;/code&gt; field determines how much browser UI is hidden when your application launches:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;standalone&lt;/code&gt;: Hides standard browser navigation bars, making the app feel native.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;minimal-ui&lt;/code&gt;: Keeps basic back/refresh controls (ideal for multi-page web apps).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fullscreen&lt;/code&gt;: Takes over the entire display (common for games).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pairing &lt;code&gt;"display": "standalone"&lt;/code&gt; with &lt;code&gt;theme_color&lt;/code&gt; and &lt;code&gt;background_color&lt;/code&gt; controls the system status bar and initial splash screen background:&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;"DevTools Suite"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"short_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;"DevTools"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"start_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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;"display"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"standalone"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"background_color"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#0f172a"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"theme_color"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"#3b82f6"&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;On iOS Safari, &lt;code&gt;manifest.json&lt;/code&gt; display modes were historically ignored in favor of proprietary &lt;code&gt;&amp;lt;meta name="apple-mobile-web-app-capable" content="yes"&amp;gt;&lt;/code&gt; tags. While modern iOS versions parse &lt;code&gt;manifest.json&lt;/code&gt;, fallback meta tags are still essential to ensure safe-area insets (&lt;code&gt;env(safe-area-inset-top)&lt;/code&gt;) render correctly without clipping status bar text.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. MIME Type and CORS Requirements
&lt;/h3&gt;

&lt;p&gt;Even a perfectly formatted manifest file will fail if your web server mis configures HTTP headers. Web Application Manifests should be served with the header:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Content-Type: application/manifest+json
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While browsers often accept &lt;code&gt;application/json&lt;/code&gt;, serving manifests as &lt;code&gt;text/html&lt;/code&gt; (a common issue in single-page apps with catch-all routing) will fail silently. Furthermore, if your manifest or icon assets are hosted on a CDN or secondary origin, cross-origin requests must include CORS headers (&lt;code&gt;Access-Control-Allow-Origin: *&lt;/code&gt;), and your HTML link tag must include &lt;code&gt;crossorigin="use-credentials"&lt;/code&gt; or &lt;code&gt;crossorigin="anonymous"&lt;/code&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  Debugging Your Manifest
&lt;/h3&gt;

&lt;p&gt;Before deploying to production, open Chrome DevTools, navigate to the &lt;strong&gt;Application&lt;/strong&gt; tab, and select &lt;strong&gt;Manifest&lt;/strong&gt;. Chrome will display real-time validation errors, icon previews, and test install triggers.&lt;/p&gt;

&lt;p&gt;Creating a solid Web App Manifest requires checking path scopes, pixel dimensions, display modes, and server headers. For rapid generation and testing without manual JSON syntax errors, try the &lt;a href="https://nutilz.com/pwa-manifest-generator" rel="noopener noreferrer"&gt;Nutilz PWA Manifest Generator&lt;/a&gt; to produce clean manifest files for your next web project.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>pwa</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Base64 Image Decoding in JavaScript: Data URL Pitfalls, Memory Overhead, and Browser Limits</title>
      <dc:creator>Rasika Dangamuwa</dc:creator>
      <pubDate>Fri, 07 Aug 2026 11:01:46 +0000</pubDate>
      <link>https://dev.to/rasika_dangamuwa_ed1074fe/base64-image-decoding-in-javascript-data-url-pitfalls-memory-overhead-and-browser-limits-1o37</link>
      <guid>https://dev.to/rasika_dangamuwa_ed1074fe/base64-image-decoding-in-javascript-data-url-pitfalls-memory-overhead-and-browser-limits-1o37</guid>
      <description>&lt;p&gt;Handling images as Base64 strings is common in modern web development. Whether receiving generated image outputs from AI models like DALL-E or Midjourney, capturing HTML5 &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt; exports with &lt;code&gt;toDataURL()&lt;/code&gt;, or embedding inline icons in JSON payloads, Base64 offers a convenient plain-text transport wrapper.&lt;/p&gt;

&lt;p&gt;However, treating Base64 binary encoding as just another string leads to subtle performance bottlenecks, memory leaks, and browser rendering bugs. Here is what happens under the hood when decoding Base64 images in production and how to handle them efficiently.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Cost of Text-Encoded Binaries
&lt;/h2&gt;

&lt;p&gt;Base64 encoding maps raw binary data onto 64 printable ASCII characters (&lt;code&gt;A-Z&lt;/code&gt;, &lt;code&gt;a-z&lt;/code&gt;, &lt;code&gt;0-9&lt;/code&gt;, &lt;code&gt;+&lt;/code&gt;, &lt;code&gt;/&lt;/code&gt;), using &lt;code&gt;=&lt;/code&gt; for padding. Because 6 bits of data are packed into each 8-bit ASCII character, Base64 increases file size by roughly 33% (specifically, &lt;code&gt;ceil(n / 3) * 4&lt;/code&gt; bytes).&lt;/p&gt;

&lt;p&gt;A 3 MB high-resolution JPEG becomes a 4 MB Base64 string in JSON. In mobile web applications or memory-constrained client environments, this payload size inflation affects parse times and network transport.&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="c1"&gt;// Byte size calculation for raw vs Base64 encoded data&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getBase64DecodedSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;base64String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Strip data URL scheme prefix if present (e.g. data:image/png;base64,)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cleanString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;base64String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/^data:image&lt;/span&gt;&lt;span class="se"&gt;\/[&lt;/span&gt;&lt;span class="sr"&gt;a-z&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+;base64,/&lt;/span&gt;&lt;span class="p"&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;paddingCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cleanString&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/=+$/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;''&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="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;cleanString&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;paddingCount&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;sampleBase64&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==&lt;/span&gt;&lt;span class="dl"&gt;"&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="s2"&gt;`Original binary size: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;getBase64DecodedSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sampleBase64&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; bytes`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Output: 70 bytes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Common Base64 Image Handling Traps
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Direct &lt;code&gt;src&lt;/code&gt; Attribute Bloat
&lt;/h3&gt;

&lt;p&gt;Setting a massive Base64 Data URL directly into an &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag's &lt;code&gt;src&lt;/code&gt; attribute is common, but risky:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ..."&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Browsers must keep the entire multi-megabyte string in the DOM tree, parse it on every layout recalculation, and hold both the string representation and decoded bitmap buffer in RAM simultaneously. For lists or galleries, this can quickly trigger browser tab crashes.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Naive &lt;code&gt;atob()&lt;/code&gt; Memory Spikes
&lt;/h3&gt;

&lt;p&gt;When converting Base64 strings to &lt;code&gt;Blob&lt;/code&gt; or &lt;code&gt;File&lt;/code&gt; objects for client-side processing, naive loop implementations create thousands of temporary string objects in memory:&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="c1"&gt;// Slow, memory-intensive conversion&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;base64ToBlobNaive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mimeType&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;byteCharacters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;atob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;base64&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;'&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;byteNumbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;byteCharacters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;byteCharacters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;byteNumbers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;byteCharacters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;charCodeAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&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;byteArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;byteNumbers&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Blob&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;byteArray&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mimeType&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;Creating a JavaScript &lt;code&gt;Array&lt;/code&gt; before wrapping it in &lt;code&gt;Uint8Array&lt;/code&gt; doubles memory consumption during execution.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Missing or Malformed MIME Headers
&lt;/h3&gt;

&lt;p&gt;Data URLs require explicit MIME type headers (&lt;code&gt;data:image/png;base64,...&lt;/code&gt;). If raw Base64 output from backend microservices lacks this header, attempting to assign it directly to image targets or canvas contexts fails silently without rendering.&lt;/p&gt;

&lt;p&gt;When inspecting unformatted strings or debugging API payloads, in-browser utilities like the &lt;a href="https://nutilz.com/base64-to-image" rel="noopener noreferrer"&gt;Nutilz Base64 to Image&lt;/a&gt; converter allow instant visual verification and image format detection without uploading payload data to external servers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performant Base64 to Blob Conversion
&lt;/h2&gt;

&lt;p&gt;To decode Base64 strings efficiently in modern JavaScript without excessive memory allocation:&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;base64ToBlob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;base64Data&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;parts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;base64Data&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&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;mimeMatch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;parts&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="nf"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/:&lt;/span&gt;&lt;span class="se"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;.*&lt;/span&gt;&lt;span class="se"&gt;?)&lt;/span&gt;&lt;span class="sr"&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;mimeType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mimeMatch&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;mimeMatch&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="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;image/png&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;base64String&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;parts&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="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;parts&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;binaryString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;atob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;base64String&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;len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;binaryString&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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;bytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Uint8Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;len&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;len&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;binaryString&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;charCodeAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Blob&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mimeType&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Convert Base64 to Object URL for lightweight DOM binding&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;base64ToBlob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sampleBase64&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;objectUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createObjectURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blob&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;img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;img&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;objectUrl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Clean up memory when image is no longer needed&lt;/span&gt;
&lt;span class="nx"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;revokeObjectURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;objectUrl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using &lt;code&gt;URL.createObjectURL(blob)&lt;/code&gt; allows the browser to reference binary data directly from memory via a lightweight pointer URL (&lt;code&gt;blob:https://...&lt;/code&gt;), reducing DOM string footprint.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;When working with Base64 images:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Convert Base64 strings to &lt;code&gt;Blob&lt;/code&gt; objects and use &lt;code&gt;URL.createObjectURL&lt;/code&gt; instead of setting long data URIs on &lt;code&gt;img.src&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Always revoke object URLs (&lt;code&gt;URL.revokeObjectURL&lt;/code&gt;) when images unmount or finish loading to prevent browser memory leaks.&lt;/li&gt;
&lt;li&gt;Keep payloads binary (e.g. &lt;code&gt;multipart/form-data&lt;/code&gt; or array buffers) whenever possible for network transfer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For quick manual inspection during development or API testing, tools like the &lt;a href="https://nutilz.com/base64-to-image" rel="noopener noreferrer"&gt;Nutilz Base64 to Image Converter&lt;/a&gt; decode strings entirely on the client side without server roundtrips.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>frontend</category>
      <category>programming</category>
    </item>
    <item>
      <title>Bcrypt Under the Hood: Cost Factors, the 72-Byte Limit, and Common Hashing Pitfalls</title>
      <dc:creator>Rasika Dangamuwa</dc:creator>
      <pubDate>Fri, 07 Aug 2026 09:01:39 +0000</pubDate>
      <link>https://dev.to/rasika_dangamuwa_ed1074fe/bcrypt-under-the-hood-cost-factors-the-72-byte-limit-and-common-hashing-pitfalls-3h7c</link>
      <guid>https://dev.to/rasika_dangamuwa_ed1074fe/bcrypt-under-the-hood-cost-factors-the-72-byte-limit-and-common-hashing-pitfalls-3h7c</guid>
      <description>&lt;p&gt;Setting up user authentication or seeding databases for local development usually feels straightforward—until silent password truncation or unexpected server latency hits production. While bcrypt remains one of the most widely adopted password hashing algorithms, its internal mechanics introduce subtle edge cases that catch developers off guard.&lt;/p&gt;

&lt;p&gt;Here is what happens under the hood with bcrypt, why key limits exist, and how to avoid breaking your auth pipeline.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. The 72-Byte Truncation Trap
&lt;/h3&gt;

&lt;p&gt;The most notorious trap in bcrypt is its strict input limit: &lt;strong&gt;bcrypt only processes the first 72 bytes of any password&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Because bcrypt is built on the Blowfish cipher, input strings longer than 72 bytes are silently truncated. Bytes beyond position 71 are completely ignored during key expansion.&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="c1"&gt;// In Node.js / bcryptjs&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pass1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;72&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="s2"&gt;SECRET_KEY_123456789&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;pass2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;72&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="s2"&gt;DIFFERENT_KEY_9999&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;hash1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;bcrypt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hashSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pass1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&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;hash2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;bcrypt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hashSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pass2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&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;bcrypt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compareSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pass2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hash1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// true!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both passphrases generate identical hashes because &lt;code&gt;bcrypt&lt;/code&gt; discards everything past byte 72. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Fix:&lt;/strong&gt; If your system supports long passphrases, pre-hash the user password with SHA-256 before passing it to bcrypt:&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;crypto&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;crypto&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;pepperedPassword&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sha256&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userPassword&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hex&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;finalHash&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;bcrypt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pepperedPassword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; Always convert SHA-256 output to a fixed-length string (like 64 hex characters) so it stays safely within the 72-byte window.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Anatomy of a Bcrypt Hash String
&lt;/h3&gt;

&lt;p&gt;When bcrypt outputs a hash, it packages the algorithm version, cost factor, salt, and hash into a single 60-character ASCII string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$2b$12$R9h/cIPz0gi.URNNX3kh2OPST9/PgBkqquzi.Ss7KIUgO2t0jWMUW
│  │  │                     │
│  │  │                     └─ 31-char hash value (192 bits)
│  │  └─ 22-char Radix-64 salt (128 bits)
│  └─ Cost factor (2^12 = 4,096 iterations)
└─ Schema version (2a, 2b, or 2y)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Prefix (&lt;code&gt;$2b$&lt;/code&gt;):&lt;/strong&gt; Indicates the revision of the bcrypt specification. &lt;code&gt;$2b$&lt;/code&gt; is standard across modern libraries, addressing earlier implementation quirks in &lt;code&gt;$2a$&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost Factor (&lt;code&gt;12&lt;/code&gt;):&lt;/strong&gt; The logarithmic cost parameter ($2^{\text{cost}}$ rounds).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Salt (22 chars):&lt;/strong&gt; A randomly generated 128-bit salt formatted using bcrypt's custom Radix-64 alphabet (&lt;code&gt;./0-9A-Za-z&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  3. Tuning the Cost Factor for Production vs. Testing
&lt;/h3&gt;

&lt;p&gt;Bcrypt is intentionally slow to resist brute-force attacks on specialized GPU hardware. Every increment of the cost factor doubles the CPU time required:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Cost Factor&lt;/th&gt;
&lt;th&gt;Iterations&lt;/th&gt;
&lt;th&gt;Approx. Hash Time (Modern CPU)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;~0.2 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;1,024&lt;/td&gt;
&lt;td&gt;~80 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;4,096&lt;/td&gt;
&lt;td&gt;~320 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;16,384&lt;/td&gt;
&lt;td&gt;~1.3 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A common mistake in serverless or cloud functions (e.g., AWS Lambda, Vercel) is picking a cost factor like 14. Under concurrent login spikes, CPU usage hits 100%, causing HTTP 504 gateway timeouts.&lt;/p&gt;

&lt;p&gt;For production web applications in 2026, a target hashing duration of &lt;strong&gt;250ms to 500ms&lt;/strong&gt; (typically cost 11 or 12) strikes a good balance between security and server throughput. For automated unit test suites, dropping down to cost 4 speeds up test execution dramatically.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. Practical Testing and Debugging
&lt;/h3&gt;

&lt;p&gt;When testing user migration scripts, verifying auth microservices, or creating test fixtures, running full backend builds just to hash a string can slow down development. &lt;/p&gt;

&lt;p&gt;Using a client-side tool like the &lt;a href="https://nutilz.com/bcrypt-generator" rel="noopener noreferrer"&gt;Nutilz Bcrypt Generator&lt;/a&gt; makes it easy to generate valid test hashes or verify plain text against existing hashes directly in your browser without sending sensitive strings across remote API endpoints.&lt;/p&gt;




&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Beware the 72-byte cap:&lt;/strong&gt; Pre-hash long passphrases with SHA-256 if needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Balance cost factor:&lt;/strong&gt; Aim for ~300ms hash time per password check in production.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify salt randomness:&lt;/strong&gt; Never hardcode salts; let standard bcrypt libraries manage salt generation automatically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use browser-based utilities:&lt;/strong&gt; Speed up local auth debugging using client-side tools like &lt;a href="https://nutilz.com/bcrypt-generator" rel="noopener noreferrer"&gt;Nutilz&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>security</category>
      <category>programming</category>
    </item>
    <item>
      <title>Coding Weighted Grade Algorithms: Calculating Final Exam Requirements, Category Weights, and Edge Cases</title>
      <dc:creator>Rasika Dangamuwa</dc:creator>
      <pubDate>Tue, 04 Aug 2026 15:02:12 +0000</pubDate>
      <link>https://dev.to/rasika_dangamuwa_ed1074fe/coding-weighted-grade-algorithms-calculating-final-exam-requirements-category-weights-and-edge-47cn</link>
      <guid>https://dev.to/rasika_dangamuwa_ed1074fe/coding-weighted-grade-algorithms-calculating-final-exam-requirements-category-weights-and-edge-47cn</guid>
      <description>&lt;p&gt;Building grading algorithms, student portals, or learning management system (LMS) integrations appears simple on paper. The core formula requires multiplying category scores by their percentage weights and summing the result. Because the arithmetic is standard high school algebra, developers often write a quick loop and ship the feature.&lt;/p&gt;

&lt;p&gt;However, when building production grade calculators and academic progress tools, naive implementations quickly break. Subtle edge cases—such as incomplete term weight normalization, target final exam calculations yielding impossible percentages, and floating-point rounding drift—frequently cause discrepancies in student grade reports.&lt;/p&gt;

&lt;p&gt;Here is a breakdown of why weighted grade math fails in production and how to implement a resilient calculation algorithm.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Incomplete Term Weight Normalization
&lt;/h3&gt;

&lt;p&gt;During an academic term, student grades are constantly updating. Suppose a course syllabus divides grading into three categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Homework&lt;/strong&gt;: 30% weight&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Midterm Exam&lt;/strong&gt;: 30% weight&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Final Exam&lt;/strong&gt;: 40% weight&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Halfway through the semester, a student has received grades for Homework (85%) and the Midterm (90%), while the Final Exam has not occurred yet. &lt;/p&gt;

&lt;p&gt;A naive accumulator sums the weighted points directly:&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="c1"&gt;// BUG: Hardcoding full syllabus weight during mid-semester&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rawWeightedScore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.85&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.90&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.30&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 0.255 + 0.270 = 0.525 (52.5%)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without normalizing for the remaining 40% unearned weight, the student's running average appears as an F (52.5%). To compute an accurate current standing, your algorithm must dynamically scale the earned points by the &lt;strong&gt;sum of active weights&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;$$\text{Current Standing} = \frac{\sum (\text{Score}_i \times \text{Weight}_i)}{\sum \text{Active Weight}_i} = \frac{0.525}{0.30 + 0.30} = 87.5\%$$&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Calculating Required Final Exam Scores (Target Grade Math)
&lt;/h3&gt;

&lt;p&gt;A primary feature in student grade applications is answering: &lt;em&gt;"What score do I need on the final exam to get an A in the class?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The formula to solve for the required score on a remaining assignment ($W_{final}$) given a target overall grade ($G_{target}$) is:&lt;/p&gt;

&lt;p&gt;$$\text{Score}&lt;em&gt;{final} = \frac{G&lt;/em&gt;{target} - \sum (\text{Score}&lt;em&gt;{current} \times W&lt;/em&gt;{current})}{W_{final}}$$&lt;/p&gt;

&lt;p&gt;When writing this function, developers often forget boundary validations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Already Secured Target&lt;/strong&gt;: If $\text{Score}_{final} \le 0$, the student has already locked in the target grade even if they score 0% on the final. Displaying &lt;em&gt;"You need -15% on the final"&lt;/em&gt; looks unpolished.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mathematically Unreachable&lt;/strong&gt;: If $\text{Score}_{final} &amp;gt; 100\%$ (or beyond the maximum possible extra credit threshold), the target grade is impossible. Returning &lt;em&gt;"You need 114% on the final"&lt;/em&gt; without an explicit unreachable flag can mislead students.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When validating grade distribution logic or testing student portal APIs, you can cross-check your calculation output with a free online &lt;a href="https://nutilz.com/grade-calculator" rel="noopener noreferrer"&gt;Grade Calculator&lt;/a&gt; to verify that edge cases match expected academic outcomes across different weighting models.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Floating-Point Drift at Grade Cutoffs
&lt;/h3&gt;

&lt;p&gt;Grade boundaries are strict. A 89.99% is typically a B+, while 90.00% is an A-. In JavaScript and other IEEE 754 floating-point environments, multiplying fractional weights causes binary representation drift:&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="mf"&gt;0.85&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.30&lt;/span&gt; &lt;span class="c1"&gt;// Output: 0.25500000000000003&lt;/span&gt;
&lt;span class="mf"&gt;0.70&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.10&lt;/span&gt; &lt;span class="c1"&gt;// Output: 0.07&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When summing multiple weighted categories, precision errors can accumulate. A student whose true weighted score is exactly &lt;code&gt;90.00&lt;/code&gt; might evaluate to &lt;code&gt;89.99999999999999&lt;/code&gt;, triggering incorrect letter grade assignment if evaluated with strict comparison operators (&lt;code&gt;score &amp;gt;= 90.0&lt;/code&gt;).&lt;/p&gt;




&lt;h3&gt;
  
  
  Robust Implementation Pattern
&lt;/h3&gt;

&lt;p&gt;Here is a complete JavaScript implementation that handles dynamic weight normalization, required target score calculations, boundary validation, and float stabilization using &lt;code&gt;Number.EPSILON&lt;/code&gt;:&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;calculateWeightedGrade&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;categories&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;targetGrade&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;finalWeight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;activeWeightSum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;weightedPointsSum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;for &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;cat&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;categories&lt;/span&gt;&lt;span class="p"&gt;)&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="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;score&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;weight&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;continue&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="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;weight&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nx"&gt;weightedPointsSum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;score&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;activeWeightSum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;;&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="nx"&gt;activeWeightSum&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;currentGrade&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="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;NO_GRADES&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="c1"&gt;// Normalize current grade against active weights&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rawCurrentGrade&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;weightedPointsSum&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;activeWeightSum&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;stabilizedCurrent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;rawCurrentGrade&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EPSILON&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;finalTargetInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&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="nx"&gt;targetGrade&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="nx"&gt;finalWeight&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Required weighted points needed on final assignment&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;currentWeightedContribution&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;weightedPointsSum&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// assuming weights are decimals (e.g. 0.3)&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;neededPoints&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;targetGrade&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;currentWeightedContribution&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;rawNeededScore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;neededPoints&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;finalWeight&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;stabilizedNeeded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;rawNeededScore&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EPSILON&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nx"&gt;finalTargetInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;neededScore&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&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="nx"&gt;stabilizedNeeded&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;isSecured&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;stabilizedNeeded&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;isPossible&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;stabilizedNeeded&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;currentGrade&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;stabilizedCurrent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;activeWeightSum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;finalTargetInfo&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;h3&gt;
  
  
  Key Takeaways
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Normalize Partial Weights&lt;/strong&gt;: Divide total weighted score by the sum of active weights when calculating mid-term progress.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate Target Boundaries&lt;/strong&gt;: Flag required final exam scores below 0% as secured and above 100% as mathematically unreachable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stabilize Floats Prior to Letter Cutoffs&lt;/strong&gt;: Add &lt;code&gt;Number.EPSILON&lt;/code&gt; before rounding to prevent floating-point drift from missing critical grade thresholds.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For quick manual verification when auditing grading software or testing academic APIs, check out the free &lt;a href="https://nutilz.com/grade-calculator" rel="noopener noreferrer"&gt;Nutilz Grade Calculator&lt;/a&gt;—it runs completely client-side in your browser with no account or sign-up required.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
      <category>education</category>
    </item>
  </channel>
</rss>
