DEV Community

tarun Vaghasia
tarun Vaghasia

Posted on

E-way bill API errors explained: 108, 301, 604, 728 and how to handle each in code

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.

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.

The ones you will see first

108: Invalid login credentials

The API username or password was refused. It is almost never a typo. The common causes:

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

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.

604: Already generated

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 same document number 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 new document number is what creates a duplicate.

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 already_existed: true; the branch in the handler is for when you call the network directly.)

728: You can cancel within 24 hours

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.

The "wrong thing, right shape" ones

Code Message (roughly) What it usually means
301 Invalid eway bill number The 12 digits do not exist, or are not visible to your GSTIN
325 Could not retrieve data Valid number, but not yours to read
418 No record found 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
336 Could not retrieve transporter data Nothing is assigned to you as transporter on that date. Treat it as an empty list, not an error
341 Generated by you, cannot reject Rejection is for e-way bills others raised against you. Cancel your own instead
381 No Part-B / vehicle entry You tried to extend validity before any vehicle was entered. Update the vehicle first
387 No record for consolidated e-way bill The trip sheet number is wrong or not yours
658 Rate control limit exceeded The by-state transporter list allows about 50 calls per 15 minutes

Two of these are worth a special mention.

336 is not an error. 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.

381 is an ordering bug in your code. Extend validity needs a vehicle on the e-way bill. Add the vehicle (Part B) first.

Two reason-code tables you should never share

Cancelling asks for a reason code, and the e-way bill and e-invoice portals use different numbers for the same words:

Code E-way bill cancel E-invoice (IRN) cancel
1 Duplicate Duplicate
2 Order Cancelled Data entry mistake
3 Data Entry mistake Order Cancelled
4 Others Others

If you reuse one lookup table for both, half your cancellations carry the wrong reason and nothing will tell you.

Updating the vehicle uses a third table: 1 Break Down, 2 Transhipment, 3 Others, 4 First Time.

Handling them in code

Normalise the code first (strip the stray comma and anything that is not a digit), then branch on it. A small handler:

const codeOf = e => String(e.error_code || '').replace(/[^0-9]/g, '');

async function call(path, body) {
  const res = await fetch(`https://www.gstinapi.in${path}`, {
    method: 'POST',
    headers: { 'x-api-key': process.env.API_KEY, 'Content-Type': 'application/json' },
    body: JSON.stringify(body),
  });
  const data = await res.json();
  if (data.success) return data;

  switch (codeOf(data)) {
    case '108': throw new Error('API credentials refused: recreate the API user for this GSP');
    case '604': return lookupExisting(body);          // already generated: fetch it
    case '336': return { success: true, ewaybills: [] }; // empty list is normal
    case '728': throw new Error('Past the 24-hour cancel window: let it expire');
    default:    throw Object.assign(new Error(data.error), { code: codeOf(data) });
  }
}
Enter fullscreen mode Exit fullscreen mode

Two habits that save real money and time:

  1. Test without filing anything. Every call above accepts "test_mode": true and returns a sample in the live response shape, so you can build the error branches before you have a real GSTIN set up.
  2. Check the payload before you send it. 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.

A reference page

I kept the full list, with the call each code comes from, in one place: E-way bill and e-invoice API error codes. If you hit a code that is not there, tell me and I will add it.

If you are starting from zero, the credentials setup guide covers the one-time portal steps, which is where most 108s come from.

Top comments (0)