AWRA OpsHub Search

One Bad Row Rolls Back the File

A spreadsheet import here is all or nothing: one unacceptable row and the entire file is rolled back. That is the opposite of what most systems do, and it is the right choice for the specific reason that a half-loaded file is worse than no file.

Implementation & Rollout AWRA OpsHub Team 12 min read

The alternative to rejecting a file is accepting most of it, and then asking somebody to work out which rows are in.

Eight kinds of record can be loaded from a spreadsheet: suppliers, items, customers, assets, asset custodians, warehouses, locations and the chart of accounts. Other templates can be downloaded as a starting shape without being importable, which is a distinction worth knowing before planning a migration around one.

The whole file, or none of it

The import runs inside a single transaction. A row that cannot be accepted stops the import and everything already written is undone. There is no partial state, no list of rows that made it, and no need to work out where the file got to.

That is a deliberate inversion of the common behaviour, which is to import what can be imported and report the rest as errors. The common behaviour is friendlier on the first attempt and considerably worse afterwards.

  1. A partial import leaves you with two files

    The one you uploaded and the mental one containing the rows that actually landed. Every subsequent correction has to be reconciled against a state nobody wrote down.

  2. Re-uploading a corrected file becomes dangerous

    The rows that succeeded are already there. Whether the second attempt duplicates them, updates them or fails on them depends on details most people have not checked at the point they are fixing a spreadsheet at half past six.

  3. All-or-nothing makes the loop simple

    Fix the file, upload it again, and the only two outcomes are that it all worked or none of it did. Neither leaves you reasoning about a previous attempt.

The refusal happens before any of it, too

A template that is not importable and a file with no rows are both refused before the transaction opens, with a message saying which. So the two most common upload mistakes — the wrong template and an empty sheet — produce an immediate, specific answer rather than a transaction that opens and closes having done nothing.

The first row is the contract

Headings are read from the first row and everything else is matched against them. A file whose first row is data rather than headings is refused with a message saying exactly that, which is worth knowing because it is the single most common cause of an import that looks structurally fine and is not.

Comma-separated files and both common spreadsheet formats are accepted, and only the first sheet is read. A workbook with the data on the second tab imports nothing, which is a good argument for downloading the template rather than building a file from scratch.

Every import failure worth having is one that happens before anything was written.

An import is an update as often as it is a creation

Every template reports three numbers when it finishes: how many records were created, how many were updated and how many were skipped. That second number is the one people are surprised by.

Importing is a matching operation rather than an insertion. A row corresponding to a record that already exists updates it. That is what makes re-uploading a corrected file safe, and it is also what makes an import a legitimate way to apply a bulk change rather than only a way to get started.

It has a consequence worth planning for: an import can overwrite. A spreadsheet exported months ago, edited and re-uploaded will apply its own values over anything that has changed in the meantime. The safe habit is to export first and edit that, rather than to edit the file you originally loaded.

Two ways to run it, one implementation

Small uploads are processed while you wait; large ones are queued. Both run the same code, and the reason they can is that nothing in the import reads the current session — the organisation and the user are passed in explicitly.

That sounds like a technical footnote and it is the property that keeps the two paths honest. A service that reads the signed-in user works in a request and behaves differently in a queue, and the difference surfaces as records created by nobody, or an import that runs against the wrong organisation entirely.

Imported records go through the same doors

An imported asset is created through the same registration path as one typed into the form, so it gets its code, its barcode, its currency stamp and its risk evaluation the same way. Warehouse and location references are resolved through the same service that resolves them everywhere else, which is where the rule that a location belongs to one warehouse is enforced.

And an organisation's own custom fields can come in on the same row, through the same bridge that handles them elsewhere. The general principle is that an import is a bulk version of the ordinary path rather than a second way in — which is what stops imported data being subtly different from typed data in ways nobody discovers until a report disagrees with itself.

Five questions to ask about a bulk import

What happens to a bad row?

A good answer sounds like

A stated policy.

What ours actually is

The whole file is rolled back. There is no partial state to reconcile against on the next attempt.

Does re-uploading duplicate records?

A good answer sounds like

No.

What ours actually is

No. An import matches existing records and updates them, and reports created, updated and skipped counts separately.

Can an import overwrite current data?

A good answer sounds like

Yes — say so.

What ours actually is

Yes. A stale file re-uploaded applies its own values. Export first and edit the export.

Do imported records skip validation?

A good answer sounds like

No.

What ours actually is

No. Assets go through the same registration path as typed ones, and locations through the same resolution service.

Which templates can actually be imported?

A good answer sounds like

A named list.

What ours actually is

Eight: suppliers, items, customers, assets, asset custodians, warehouses, locations and the chart of accounts. Others are downloadable shapes only.

Our take

All-or-nothing is the unpopular choice and the correct one, and the argument for it is entirely about the second attempt. A partial import is generous on the first upload and leaves you reasoning about a state nobody recorded on every one after it — which is exactly the point at which somebody is tired, the file is nearly right, and a duplicate supplier list gets created. Rolling the whole thing back costs a retry and keeps the loop trivial. The one thing to be deliberate about is that imports update as well as create, so a spreadsheet is a bulk edit and not just a bulk load. Export, edit the export, upload. Anything else is applying month-old values over live records with no warning that it is what you are doing.

The import ledger, precisely

What AWRA OpsHub does today

  • Row import for eight record types: suppliers, items, customers, assets, asset custodians, warehouses, locations and the chart of accounts.
  • The whole import inside one transaction, so an unacceptable row rolls back everything and leaves no partial state.
  • Refusals before the transaction opens for an unsupported template and for a file with no rows, each with its own message.
  • Headings read from the first row, with an explicit refusal when they are absent.
  • Comma-separated and both common spreadsheet formats accepted, reading the first sheet.
  • Matching against existing records so a re-upload updates rather than duplicates, with created, updated and skipped counts reported separately.
  • One implementation used by both the immediate path for small uploads and the queued path for large ones.
  • All organisation and user context passed in explicitly rather than read from the session, so the queued path cannot behave differently from the immediate one.
  • Imported records created through the same services as typed ones, including asset registration and warehouse and location resolution.
  • An organisation's own custom fields importable on the same row through the same bridge used elsewhere.

More we can add to your workspace

  • A dry run reporting what a file would do — created, updated and refused per row — before anything is written.
  • A row-level error report naming every problem in the file at once, rather than stopping at the first.
  • A record of what an import changed, so a bulk update applied from a stale file can be identified afterwards.
  • Import for the templates that are download-only today, extending the list of eight.
  • A choice between create-only and update-allowed, for organisations that want an import that refuses to touch existing records.
  • Reading a named sheet rather than the first one, for workbooks built around a cover page.

Where we point you to a specialist

  • We will keep imports all or nothing. A partial import is friendlier once and worse every subsequent time, because it leaves an unrecorded state that the next attempt has to be reasoned against — and that reasoning happens at the end of a long day with a nearly-correct spreadsheet.
  • We will not route imported records around the checks typed records pass. An import that created assets without their registration path, or accepted a location that belongs to another warehouse, would put data into your system that is subtly different from everything around it, and the difference would only surface in a report months later.
  • Deciding whether a bulk update should overwrite what is currently in your system is your call, and the honest answer is that it will. We will report what was created and what was updated; making sure the file reflects the present rather than a month ago is a habit rather than a feature.

A dry run is the contained piece here and the one that removes the remaining friction — the same matching logic, reported rather than applied, so a file can be corrected before anything is written.

Scope, not a ceiling

Making the loop shorter

All-or-nothing keeps the mechanism safe. What would make it pleasant is finding every problem in one pass rather than one at a time.

A dry run

What the file would create, update and refuse, per row, with nothing written — the same logic, reported instead of applied.

Every error at once

A report naming each problematic row and why, so a file is corrected in one pass rather than in as many passes as it has mistakes.

A record of what an import changed

Which records a bulk update touched and what it overwrote, so a stale file applied by mistake can be found.

We publish scope, not dates.

Scope a data migration

Export before you edit

It is the single habit that separates a bulk import that helps from one that quietly reverts three weeks of changes. Export, edit the export, upload it back.

Talk through migration

Frequently asked questions

Why does one bad row reject the whole file?

Because a partial import leaves a state nobody recorded, and every subsequent attempt has to be reasoned against it. Rolling back keeps the loop trivially simple — fix the file, upload again, and the only outcomes are that it all worked or none of it did. It is generous on the first attempt to do otherwise and much worse on the second.

Will re-uploading a file create duplicates?

No. An import matches against existing records and updates them, which is why the result reports created and updated separately. That is what makes correcting and re-uploading safe, and it is also why an import is a legitimate way to apply a bulk change rather than only a way to start.

Can an import overwrite data we have changed since?

Yes, and this is the thing to be deliberate about. A spreadsheet exported two months ago, edited and re-uploaded will apply its own values over anything that has moved in the meantime, and nothing warns you that is what is happening. Export a fresh file, edit the export, and upload that.

Why did my file import nothing?

Two common causes. The first row must be headings rather than data, and only the first sheet of a workbook is read — so a file with a cover page and the data on the second tab imports nothing. Downloading the template and filling it in avoids both.

Do imported records go through the same checks?

Yes. Assets are created through the same registration path as typed ones, so they get their code, barcode, currency stamp and risk evaluation identically, and warehouse and location references resolve through the same service that enforces the rule elsewhere. An import is a bulk version of the ordinary path rather than a second way in.

Can I see what a file would do before running it?

Not today, and it is the most useful thing on the list of what would be added. A dry run using the same matching logic — reporting what would be created, updated and refused without writing anything — turns a correction cycle from several uploads into one.

Help Center

Need a quick answer while you read?

Run inventory, procurement, assets, sales, and field work with approved AWRA guidance for setup, migration, integrations, security, pricing, and support.

Search all approved AWRA public help articles.

Open Help Center