Broken commit diff on Cisco IOS XR

Vincent Bernat

Up­date (2025-10)

These is­sues are fixed in 24.2.21 + SMU, 24.4.2, and 25.1.1.

TL;DR

Never trust show commit changes diff on Cisco IOS XR.

Cisco IOS XR is the op­er­at­ing sys­tem run­ning for the Cisco ASR, NCS, and 8000 routers. Com­pared to Cisco IOS, it fea­tures a can­di­date con­fig­u­ra­tion and a run­ning con­fig­u­ra­tion. In con­fig­u­ra­tion mode, you can mod­ify the first one and is­sue the commit com­mand to ap­ply it to the run­ning con­fig­u­ra­tion.1 This is a com­mon con­cept for many NOS.

Be­fore com­mit­ting the can­di­date con­fig­u­ra­tion to the run­ning con­fig­u­ra­tion, you may want to check the changes that have ac­cu­mu­lated un­til now. That’s where the show commit changes diff com­mand2 comes up. Its goal is to show the dif­fer­ence be­tween the run­ning con­fig­u­ra­tion (show running-configuration) and the can­di­date con­fig­u­ra­tion (show configuration merge). How hard can it be?

Let’s put an in­ter­face down on IOS XR 7.6.2 (re­leased in Au­gust 2022):

RP/0/RP0/CPU0:router(config)#int Hu0/1/0/1 shut
RP/0/RP0/CPU0:router(config)#show commit changes diff
Wed Nov 23 11:08:30.275 CET
Building configuration...
!! IOS XR Configuration 7.6.2
+  interface HundredGigE0/1/0/1
+   shutdown
   !
end

The + sign be­fore interface HundredGigE0/1/0/1 makes it look like you did cre­ate a new in­ter­face. Maybe there was a typo? No, the diff is just bro­ken. If you look at the can­di­date con­fig­u­ra­tion, ev­ery­thing is like you expect:

RP/0/RP0/CPU0:router(config)#show configuration merge int Hu0/1/0/1
Wed Nov 23 11:08:43.360 CET
interface HundredGigE0/1/0/1
 description PNI: (some description)
 bundle id 4000 mode active
 lldp
  receive disable
  transmit disable
 !
 shutdown
 load-interval 30

Here is a more prob­lem­atic ex­am­ple on IOS XR 7.2.2 (re­leased in Jan­u­ary 2021). We want to un­con­fig­ure three in­terfaces:

RP/0/RP0/CPU0:router(config)#no int GigabitEthernet 0/0/0/5
RP/0/RP0/CPU0:router(config)#int TenGigE 0/0/0/5 shut
RP/0/RP0/CPU0:router(config)#no int TenGigE 0/0/0/28
RP/0/RP0/CPU0:router(config)#int TenGigE 0/0/0/28 shut
RP/0/RP0/CPU0:router(config)#no int TenGigE 0/0/0/29
RP/0/RP0/CPU0:router(config)#int TenGigE 0/0/0/29 shut
RP/0/RP0/CPU0:router(config)#show commit changes diff
Mon Nov  7 15:07:22.990 CET
Building configuration...
!! IOS XR Configuration 7.2.2
-  interface GigabitEthernet0/0/0/5
-   shutdown
   !
+  interface TenGigE0/0/0/5
+   shutdown
   !
   interface TenGigE0/0/0/28
-   description Trunk (some description)
-   bundle id 2 mode active
   !
end

The two first com­mands are cor­rectly rep­re­sented by the first two chunks of the diff: we re­move GigabitEthernet0/0/0/5 and cre­ate TenGigE0/0/0/5. The two next com­mands are also cor­rectly rep­re­sented by the last chunk of the diff. TenGigE0/0/0/28 was al­ready shut down, so it is ex­pected that only description and bundle id are re­moved. How­ever, the diff com­mand for­gets about the mod­i­fi­ca­tions for TenGigE0/0/0/29. The diff should in­clude a chunk sim­i­lar to the last one.

RP/0/RP0/CPU0:router(config)#show run int TenGigE 0/0/0/29
Mon Nov  7 15:07:43.571 CET
interface TenGigE0/0/0/29
 description Trunk to other router
 bundle id 2 mode active
 shutdown
!
RP/0/RP0/CPU0:router(config)#show configuration merge int TenGigE 0/0/0/29
Mon Nov  7 15:07:53.584 CET
interface TenGigE0/0/0/29
 shutdown
!

How can the diff be cor­rect for TenGigE0/0/0/28 but in­cor­rect for TenGigE0/0/0/29 while they have the same con­fig­u­ra­tion? How can you trust the diff com­mand if it for­gets part of the con­fig­uration?

Do you re­mem­ber the last time you ran an An­si­ble play­book and dis­cov­ered the whole router ospf block dis­ap­peared with­out a warn­ing? If you use au­to­ma­tion tools, you should check how the diff is as­sem­bled. Au­to­ma­tion tools should build it from the re­sult of show running-config and show configuration merge. This is what NAPALM does. This is not what cisco.​iosxr col­lec­tion for An­si­ble does.

The prob­lem is not lim­ited to the interface di­rec­tives. You can get sim­i­lar is­sues for other parts of the con­fig­u­ra­tion. For ex­am­ple, here is what we get when re­mov­ing in­ac­tive BGP neigh­bors on IOS XR 7.2.2:

RP/0/RP0/CPU0:router(config)#router bgp 65400
RP/0/RP0/CPU0:router(config-bgp)#vrf public
RP/0/RP0/CPU0:router(config-bgp-vrf)#no neighbor 217.29.66.1
RP/0/RP0/CPU0:router(config-bgp-vrf)#no neighbor 217.29.66.75
RP/0/RP0/CPU0:router(config-bgp-vrf)#no neighbor 217.29.66.110
RP/0/RP0/CPU0:router(config-bgp-vrf)#no neighbor 217.29.66.112
RP/0/RP0/CPU0:router(config-bgp-vrf)#no neighbor 217.29.66.158
RP/0/RP0/CPU0:router(config-bgp-vrf)#no neighbor 217.29.67.10
RP/0/RP0/CPU0:router(config-bgp-vrf)#no neighbor 217.29.67.15
RP/0/RP0/CPU0:router(config-bgp-vrf)#show commit changes diff
Tue Aug  2 13:58:02.536 CEST
Building configuration...
!! IOS XR Configuration 7.2.2
   router bgp 65400
    vrf public
-    neighbor 217.29.66.1
-     remote-as 16004
-     use neighbor-group MIX_IPV4_PUBLIC
-     description MIX: MIX-IT
     !
-    neighbor 217.29.66.75
-     remote-as 49367
-     use neighbor-group MIX_IPV4_PUBLIC
     !
-    neighbor 217.29.67.10
-     remote-as 19679
     !
-    neighbor 217.29.67.15
-    neighbor 217.29.66.112
-     remote-as 8075
-     use neighbor-group MIX_IPV4_PUBLIC
-     description MIX: Microsoft
-     address-family ipv4 unicast
-      maximum-prefix 1500 95 restart 5
      !
     !
-    neighbor 217.29.66.158
-     remote-as 24482
-     use neighbor-group MIX_IPV4_PUBLIC
-     description MIX: SG.GS
-     address-family ipv4 unicast
     !
     !
    !
   !
end

The only cor­rect chunk is for neigh­bor 217.29.66.112. All the oth­ers are miss­ing some of the re­moved lines. 217.29.67.15 is even miss­ing all of them. How bad is the code pro­vid­ing such a diff?

I could go all day with ex­am­ples such as these. Cisco TAC is happy to open a case in DDTS, their bug tracker, to fix spe­cific oc­cur­rences of this bug.3 How­ever, I fail to un­der­stand why the XR team is not just pro­vid­ing the diff be­tween show run and show configuration merge. The out­put would al­ways be correct! 🙄

Up­date (2026-10)

On Cisco Nexus, the sit­u­a­tion is not great ei­ther. Cisco NX-OS gained can­di­date con­fig­u­ra­tions in ver­sion 10.2(3)F, re­leased in 2022, and can show a diff with the run­ning con­fig­u­ra­tion since 10.6(3)F, re­leased in 2026. Yet, the fea­ture is still un­us­able today:

# configure candidate
Error: Current running-config has commands which are not supported by candidate session.
Please check the 'show candidate-config last-unsupported' and remove the unsupported configs from running-config.
# show candidate-config last-unsupported
feature isis
interface port-channel11 ; isis metric 10 level-2
interface port-channel11 ; isis network point-to-point
interface port-channel11 ; ip router isis UNDERLAY
[...]