ROSv7.20.8 /ip dns static find where name="whatever" off-by-one when run interactively?

I’ve recently bought an hEX E50UG, to start my journey to ROSv7, so that I don’t just throw my existing three RB951Ui-2HnD ROSv6 devices into “upgrade to ROSv7 and pray” mode :sweat_smile:

So far, mostly, so good. But:

My “Set DNS static entries from DHCP leases” script, which works fine on my three ROSv6 devices, throws this error in the logs of the new ROSv7 device:

2026-02-20 09:41:43 script,error executing script DNS via DHCP v2 from scheduler (DNS via DHCP v2) failed, please check it manually
2026-02-20 09:41:43 script,error,debug invalid internal item number (/ip/dns/static/get; line 36)

This isn’t a “fatal, stop, the script doesn’t work at all” error. The script does seem to mostly work.

So I ran some of the script commands manually, and I figured out the following:

  1. I’m an idiot. The script was erroring because I had BOTH an A and a CNAME record for “oneofmyhostnames.mydomain.org”, which, the way the script is written, totally should throw an error. :man_facepalming:
  2. It looks like the /ip dns static find where name=”whatever” command is returning an off-by-one index into the DNS static table, except, clearly, since the script works, it isn’t.

Which (2. above) leads to the question, why does running the command interactively return an off-by-one index?

Example:

[admin@MikroTik4.felines.org] > /ip dns static print
Columns: NAME, TYPE, ADDRESS, TTL

NAME TYPE ADDRESS TTL

;;; defconf
0 router.lan A 192.168.88.1 1d
;;; automatic-from-dhcp (magic comment)
1 JayThinkP51-2.felines.org A 192.168.255.13 15m
;;; automatic-from-dhcp (magic comment)
2 YYThink.felines.org A 192.168.255.17 15m
;;; automatic-from-dhcp (magic comment)
3 TL-WPA8630P.felines.org A 192.168.255.8 15m

8 MikroTik1.felines.org A 192.168.255.3 1d
9 MikroTik2.felines.org A 192.168.254.3 1d

22 AVClientXR2 CNAME 1d
23 Monster CNAME 1d
;;; automatic-from-dhcp (magic comment)
24 Ajax-001BA5CE.felines.org A 192.168.255.4 15m

Let’s look up a couple of entries:

[admin@MikroTik4.felines.org] > :put [/ip dns static find where name="router.lan"]
*1

[admin@MikroTik4.felines.org] > :put [/ip dns static find where name="MikroTik1.felines.org"]
*9

Um. But. In the /ip dns static print output above, router.lan is line 0, and MikroTik1.felines.org is line 8.

So, it seems “cosmetic”, but, why?

thanks,
-Jay

database index (.id) is not the column number on print results, like excel (ignoring that counting start from 0 instead from 1)

So, what script command should be used, in the interactive (command line) context, to get the line number in the output of (e.g. in /ip/dns/static) “print” that would match the “where” clause?

Or, is that not supported/ it’s not useful?

Could we turn it around – how can I, interactively, /ip/dns/static print where [THE DATABASE ROW Id NUMBER]=$somevarvalue
?

thanks, from an ancient C and PERL programmer …

you must never use .id or "number" on scripting.

"number" is only useful ONCE (but can be same number necxt time) on CLI, used manually....

You need to provide a concrete example of what you want to do on CLI... I can't explain without one.

If the output (interactively typed at the command prompt, not in a script which is automatically executed) of:

:put [/ip dns static find where name=”somehostname”]

happens to be

*6

for example, then how would I, as the interactive command:

/ip/dns/static print where WHAT_FIELD_NAME=6

.. to print out the actual table row with database Id 6 as was output by the :put command above?

Or are scripts scripts, and eyeballing stuff manually is eyeballing stuff manually, and really I’m asking something for which there’s never a practical need to be able to do it?

where .id=*6

:sweat_smile: Well, now don’t I feel foolish…

thank you, all!

A more interesting usage is:
:put [ /ip/dns/static get *6 ]
(Get returns the entire "object" as a dictionary.)

Better not use .id or numbers...

:put [/ip dns static get [find where name="oneofmyhostnames.mydomain.org" and type=A]]
:put [/ip dns static get [find where name="oneofmyhostnames.mydomain.org" and type=CNAME]]

results EXAMPLE:

[@] > :put [/ip dns static get [find where name="oneofmyhostnames.mydomain.org" and type=A]]
.id=*1;.nextid=*2;address=10.10.10.10;disabled=false;dynamic=false;name=oneofmyhostnames.mydomain.org;ttl=1d00:00:00;type=A
[@] > :put [/ip dns static get [find where name="oneofmyhostnames.mydomain.org" and type=CNAME]]
.id=*2;.nextid=*ffffffff;cname=abc.mydomain.org;disabled=false;dynamic=false;name=oneofmyhostnames.mydomain.org;ttl=1d00:00:00;type=CNAME
[@] >

especially when you don't know the meaning of wanting to print the ".id"

and especially when the wrong "quotation marks" are used...

" is not

name=somehostname is the same as name="”somehostname”",
so never find somehostname because ... became a part of the search string, and is not the string delimiter...

1 Like

I hate to say it, but AI e.g. Claude is brilliant at ROS scripting… No doubt it learnt from this forum!

Sorry, but why did you write this?
No allusion, just curiosity...

What brought all of this on was wanting to be able to reproduce at the command line the effects of commands in scripts. Since the scripts magically handle objects returned from [find commands, I was looking for how to do the same thing interactively. This very nice detailed conversation fulfilled that very well. Thanks again to everyone.

As such, the .id might actually be useful, for script debugging.

About the “quotes” appearing one way or another in my various posts, I’m fairly sure that this was the forum software (possibly the fact that I used the “quote” functionality to offset some of my literal text and examples), and/or Windows/ web browser/ forum software language-region side-effects. I live among English (US), English (UK/Ireland), Spanish (Peninsular), Catalan, and German, so I’m unfortunately familiar with the various types of quotes (and the mayhem they can cause)…

1 Like

Examples...

[@] > /ip dns static
[@] /ip/dns/static> print
Columns: NAME, TYPE, ADDRESS, TTL
# NAME       TYPE  ADDRESS  TTL
0 rara.site  A     7.8.9.0  1d 
1 test.site  A     2.3.4.5  1d 
[@] /ip/dns/static> set 1 address=6.7.8.9
[@] /ip/dns/static> pri
Columns: NAME, TYPE, ADDRESS, TTL
# NAME       TYPE  ADDRESS  TTL
0 rara.site  A     7.8.9.0  1d 
1 test.site  A     6.7.8.9  1d 
[@] /ip/dns/static> 
[@] > /ip dns static
[@] /ip/dns/static> pri
Columns: NAME, TYPE, ADDRESS, TTL
# NAME          TYPE   ADDRESS  TTL
0 test.site     A      6.7.8.9  1d 
1 aiculedd.sul  CNAME           1d 
[@] /ip/dns/static> set [find] comment="all static aldrady presents"   
[@] /ip/dns/static> pri
Columns: NAME, TYPE, ADDRESS, TTL
# NAME          TYPE   ADDRESS  TTL
;;; all static aldrady presents
0 test.site     A      6.7.8.9  1d 
;;; all static aldrady presents
1 aiculedd.sul  CNAME           1d 
[@] /ip/dns/static> set [find where type=CNAME] comment="all CNAMEs aleady presents"         
[@] /ip/dns/static> pri
Columns: NAME, TYPE, ADDRESS, TTL
# NAME          TYPE   ADDRESS  TTL
;;; all static aldrady presents
0 test.site     A      6.7.8.9  1d 
;;; all CNAMEs aleady presents
1 aiculedd.sul  CNAME           1d 
[@] /ip/dns/static> 

RouterOS does not correct syntax errors in comments.... :rofl:

1 Like

Point taken. Perhaps a new topic on “AI” + ros scripting is required…

You can get all DNS records as a dictionary array:
:local myDNS [/ip dns static print detail as-value]
In this array, the record index will correspond to the row number in the table you see, and this same index, for example, can be used in the command
ip dns static/disable numbers=

1 Like

RouterOS scripting remains me a little bit about what they said about the C programming language when I learned it in the 1980s (although this specific quote that I’ve just found is somewhat newer than that) -
”Bjarne Stroustrup's observation: “C makes it easy to shoot yourself in the foot.””

(More or less, you CAN do ANYTHING, but you’re LIKELY to do EVERYTHING :ghost:)