<?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: tarun Vaghasia</title>
    <description>The latest articles on DEV Community by tarun Vaghasia (@tarun_vaghasia_254285d667).</description>
    <link>https://dev.to/tarun_vaghasia_254285d667</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%2F4210156%2F35872ba8-5d4b-4f85-925c-b2a627b68ed1.jpg</url>
      <title>DEV Community: tarun Vaghasia</title>
      <link>https://dev.to/tarun_vaghasia_254285d667</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tarun_vaghasia_254285d667"/>
    <language>en</language>
    <item>
      <title>E-way bill API errors explained: 108, 301, 604, 728 and how to handle each in code</title>
      <dc:creator>tarun Vaghasia</dc:creator>
      <pubDate>Tue, 27 Oct 2026 07:07:04 +0000</pubDate>
      <link>https://dev.to/tarun_vaghasia_254285d667/e-way-bill-api-errors-explained-108-301-604-728-and-how-to-handle-each-in-code-3h4g</link>
      <guid>https://dev.to/tarun_vaghasia_254285d667/e-way-bill-api-errors-explained-108-301-604-728-and-how-to-handle-each-in-code-3h4g</guid>
      <description>&lt;p&gt;If you generate e-way bills or e-invoices from code, you will meet the same handful of error codes again and again. The messages are terse, the codes sometimes arrive with a stray comma ("301,"), and a couple of them mean the opposite of what a retry loop assumes.&lt;/p&gt;

&lt;p&gt;This is the list I wish I had when I started. Every code below is one I actually hit against the live network, not one I copied from a PDF.&lt;/p&gt;

&lt;h2&gt;
  
  
  The ones you will see first
&lt;/h2&gt;

&lt;h3&gt;
  
  
  108: Invalid login credentials
&lt;/h3&gt;

&lt;p&gt;The API username or password was refused. It is almost never a typo. The common causes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The API user was created for a &lt;strong&gt;different GSP&lt;/strong&gt; (for example inside your accounting software). An API user only works with the GSP it was created for.&lt;/li&gt;
&lt;li&gt;The password has special characters. Letters and digits only is the safe choice.&lt;/li&gt;
&lt;li&gt;You sent your normal portal login instead of the API user.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fix: create a fresh API user for the GSP you are calling through (e-way bill portal: Registration, then For GSP). The e-invoice portal has its own separate API user, even for the same GSTIN.&lt;/p&gt;

&lt;h3&gt;
  
  
  604: Already generated
&lt;/h3&gt;

&lt;p&gt;You sent a document that already has an e-way bill. This is the one that bites retry loops. If your first call timed out, you do not know whether the e-way bill was filed. Retrying with the &lt;strong&gt;same document number&lt;/strong&gt; cannot create a duplicate: the network answers 604, and the existing e-way bill can be fetched by document type and number. Generating with a &lt;em&gt;new&lt;/em&gt; document number is what creates a duplicate.&lt;/p&gt;

&lt;p&gt;The clean pattern: on a timeout, retry the same payload, and treat 604 as "go and fetch the existing one", not as a failure. (The API used in the example below does that recovery for you and returns the real e-way bill with &lt;code&gt;already_existed: true&lt;/code&gt;; the branch in the handler is for when you call the network directly.)&lt;/p&gt;

&lt;h3&gt;
  
  
  728: You can cancel within 24 hours
&lt;/h3&gt;

&lt;p&gt;Cancellation is only possible within 24 hours, by the generator. After that there is no API to undo it; you let it expire and issue a correct one. If you generate e-way bills while testing, cancel them in the same session. They cannot be cancelled tomorrow.&lt;/p&gt;

&lt;h2&gt;
  
  
  The "wrong thing, right shape" ones
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Code&lt;/th&gt;
&lt;th&gt;Message (roughly)&lt;/th&gt;
&lt;th&gt;What it usually means&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;301&lt;/td&gt;
&lt;td&gt;Invalid eway bill number&lt;/td&gt;
&lt;td&gt;The 12 digits do not exist, or are not visible to your GSTIN&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;325&lt;/td&gt;
&lt;td&gt;Could not retrieve data&lt;/td&gt;
&lt;td&gt;Valid number, but not yours to read&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;418&lt;/td&gt;
&lt;td&gt;No record found&lt;/td&gt;
&lt;td&gt;A lookup by document number found nothing. The document type must match what was filed: a challan (CHL) is not found when you ask for INV&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;336&lt;/td&gt;
&lt;td&gt;Could not retrieve transporter data&lt;/td&gt;
&lt;td&gt;Nothing is assigned to you as transporter on that date. Treat it as an empty list, not an error&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;341&lt;/td&gt;
&lt;td&gt;Generated by you, cannot reject&lt;/td&gt;
&lt;td&gt;Rejection is for e-way bills others raised against you. Cancel your own instead&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;381&lt;/td&gt;
&lt;td&gt;No Part-B / vehicle entry&lt;/td&gt;
&lt;td&gt;You tried to extend validity before any vehicle was entered. Update the vehicle first&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;387&lt;/td&gt;
&lt;td&gt;No record for consolidated e-way bill&lt;/td&gt;
&lt;td&gt;The trip sheet number is wrong or not yours&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;658&lt;/td&gt;
&lt;td&gt;Rate control limit exceeded&lt;/td&gt;
&lt;td&gt;The by-state transporter list allows about 50 calls per 15 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two of these are worth a special mention.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;336 is not an error.&lt;/strong&gt; The network answers an empty transporter list with an error code. If you surface it to a user as a failure, you will get a support ticket for every quiet day.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;381 is an ordering bug in your code.&lt;/strong&gt; Extend validity needs a vehicle on the e-way bill. Add the vehicle (Part B) first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two reason-code tables you should never share
&lt;/h2&gt;

&lt;p&gt;Cancelling asks for a reason code, and the e-way bill and e-invoice portals use &lt;strong&gt;different numbers for the same words&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Code&lt;/th&gt;
&lt;th&gt;E-way bill cancel&lt;/th&gt;
&lt;th&gt;E-invoice (IRN) cancel&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Duplicate&lt;/td&gt;
&lt;td&gt;Duplicate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Order Cancelled&lt;/td&gt;
&lt;td&gt;Data entry mistake&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Data Entry mistake&lt;/td&gt;
&lt;td&gt;Order Cancelled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Others&lt;/td&gt;
&lt;td&gt;Others&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you reuse one lookup table for both, half your cancellations carry the wrong reason and nothing will tell you.&lt;/p&gt;

&lt;p&gt;Updating the vehicle uses a third table: 1 Break Down, 2 Transhipment, 3 Others, 4 First Time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling them in code
&lt;/h2&gt;

&lt;p&gt;Normalise the code first (strip the stray comma and anything that is not a digit), then branch on it. A small handler:&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;codeOf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error_code&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;replace&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;0-9&lt;/span&gt;&lt;span class="se"&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="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&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="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://www.gstinapi.in&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&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;x-api-key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&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="p"&gt;});&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;success&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;codeOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;108&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;API credentials refused: recreate the API user for this GSP&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;604&lt;/span&gt;&lt;span class="dl"&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;lookupExisting&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="c1"&gt;// already generated: fetch it&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;336&lt;/span&gt;&lt;span class="dl"&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;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;ewaybills&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt; &lt;span class="c1"&gt;// empty list is normal&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;728&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Past the 24-hour cancel window: let it expire&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nl"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;codeOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two habits that save real money and time:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Test without filing anything.&lt;/strong&gt; Every call above accepts &lt;code&gt;"test_mode": true&lt;/code&gt; and returns a sample in the live response shape, so you can build the error branches before you have a real GSTIN set up.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check the payload before you send it.&lt;/strong&gt; A local validator catches the mechanical mistakes (an HSN code that is not 4, 6 or 8 digits, tax amounts that do not match the taxable value at the stated rate) without a network call. Passing it is not approval: a cancelled GSTIN or a duplicate document is only caught by the network.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  A reference page
&lt;/h2&gt;

&lt;p&gt;I kept the full list, with the call each code comes from, in one place: &lt;a href="https://www.gstinapi.in/e-way-bill-api-errors" rel="noopener noreferrer"&gt;E-way bill and e-invoice API error codes&lt;/a&gt;. If you hit a code that is not there, tell me and I will add it.&lt;/p&gt;

&lt;p&gt;If you are starting from zero, the &lt;a href="https://www.gstinapi.in/e-way-bill-e-invoice-api-credentials" rel="noopener noreferrer"&gt;credentials setup guide&lt;/a&gt; covers the one-time portal steps, which is where most 108s come from.&lt;/p&gt;

</description>
      <category>api</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>india</category>
    </item>
  </channel>
</rss>
