How to Fix Disconnected Edges in Utility Topology

Disconnected edges in a utility network topology are a graph-integrity failure that quietly corrupts every downstream result: trace paths terminate early, isolation boundaries land in the wrong place, and outage-impact counts under-report affected customers. At the scale of a real distribution system — hundreds of thousands of conductors, mains, or conduits edited daily by field crews — hunting and re-snapping these breaks by hand in an editing session is neither auditable nor repeatable, and a single missed gap can invalidate a safety-critical isolation plan. The reliable fix is a schema-aware, scripted procedure that diagnoses the cause before it touches geometry, repairs within a defined tolerance, and proves the repair with a re-run trace.

From a micro-gap to a re-validated edge: the four-stage repair flow On the left, an edge endpoint stops just short of a junction, leaving a sub-tolerance micro-gap that the topology engine refuses to connect. An arrow leads to four sequential repair stages: detect unconnected endpoints, snap within tolerance, rebuild the connectivity association, and re-validate with a connected trace. The defect gap micro- edge end junction Smaller than capture precision, larger than XY tolerance. The scripted repair 1. Detect endpoints with Join_Count = 0 2. Snap to junction within tolerance 3. Associate rebuild connectivity 4. Re-validate + connected trace Trace returns features ⇒ integrity proven. Zero / early stop ⇒ back to schema checks. on failure
Diagnose the cause, repair within a confirmed tolerance, then prove the fix with a re-run connected trace; a failed trace loops back to the schema checks rather than re-snapping geometry.

Environment Prerequisites

Confirm every item below before running any repair. A mismatch in any one of them is the most common reason a “successful” snap still leaves the edge logically disconnected.

  • ArcGIS Pro 3.1 or later with the Utility Network user type extension licensed and the network owner credentials available.
  • Enterprise or file geodatabase hosting the Utility Network, with the topology enabled and no active schema locks (close all editing sessions and reconcile/post outstanding versions).
  • Python 3.9+ with arcpy from the ArcGIS Pro conda environment (clone the default arcgispro-py3 env so dependencies stay isolated).
  • Known XY tolerance and spatial reference for the network — typically 0.0010.01 m depending on coordinate system precision and capture method. This must be confirmed against the source data, not assumed.
  • Read/write access to the connectivity rule table so association rules for the affected asset types can be inspected and, if missing, added.
  • A validated baseline: run a clean topology validation pass first so you are repairing genuine breaks, not stale dirty areas.

Schema-Aware Validation Protocol (Before You Snap)

Disconnected edges arise from three failure modes, and the order in which you check them matters — fixing geometry before fixing the schema simply re-creates the break on the next validate. Work the list top-down; the most common root cause is first.

  1. Spatial tolerance misalignment (most common). When CAD imports, field GPS captures, or legacy migrations introduce micro-gaps smaller than your capture precision but larger than the network XY tolerance, the topology engine refuses to connect coincident-looking features. Compare the network’s XY Tolerance property against the source dataset’s resolution before adjusting anything. This is the same precision discipline covered in CRS alignment and geodetic transformations — a datum or projection drift upstream surfaces here as systematic snapping failure.
  2. Missing or invalid connectivity rules. Each asset type needs an explicit connectivity association rule for its lifecycle state. If a feature class has no valid policy, the topology ignores spatial intersections entirely — the geometry is perfect and the edge is still orphaned. Audit the rule table the same way you would when configuring connectivity rules for pipe and cable, confirming the FromAssetType/ToAssetType pair is permitted.
  3. Lifecycle state mismatch. An edge marked InService cannot logically connect to a junction in a Retired state without an approved transition rule, even when the two are spatially coincident. Check LifecycleStatus on both endpoints before assuming a geometry problem.

Materialize the evidence rather than eyeballing it: run a targeted validation against the Edge Connectivity and Junction-Edge rules, then export the resulting error features to a geodatabase table so the repair script reads from a deterministic input. This diagnostic-first pass is exactly the discipline formalized in the parent automated error handling and flagging workflow.

Minimal Reproducible Implementation

The routine below extracts edge endpoints, identifies those with no junction within tolerance, snaps the flagged endpoints, rebuilds the connectivity associations, and returns a structured result for logging. It handles geoprocessing failures explicitly and cleans up its in-memory scratch datasets so it is safe to schedule. Adjust the configuration block to your network — the tolerance value in particular must match the network spatial-reference precision you confirmed above.

import arcpy
import logging

# Structured logging for an auditable repair trail.
logging.basicConfig(
    filename="un_edge_remediation.log",
    level=logging.INFO,
    format="%(asctime)s | %(levelname)s | %(message)s",
)

# --- Configuration (confirm every value against your network) ---
gdb = r"C:\UtilityNetwork\Network.gdb"
un_name = "UN_Electric"
edge_fc = f"{un_name}\\DistributionLine"
junction_fc = f"{un_name}\\Junction"
tolerance = 0.005  # Meters — MUST match the UN spatial-reference precision.

arcpy.env.workspace = gdb
arcpy.env.overwriteOutput = True


def repair_disconnected_edges():
    """Detect, snap, and re-associate disconnected edge endpoints.

    Returns a dict with the count of endpoints flagged and repaired so the
    caller (CI job, work-order hook) can act on a structured result.
    """
    result = {"flagged": 0, "snapped": False}
    endpoints_fc = "memory\\edge_endpoints_temp"
    spatial_join = "memory\\spatial_validation_temp"
    try:
        # 1. Extract both endpoints of every edge as point features.
        arcpy.management.FeatureVerticesToPoints(edge_fc, endpoints_fc, "BOTH_ENDS")

        # 2. Spatial join: which endpoints have NO junction within tolerance?
        arcpy.analysis.SpatialJoin(
            endpoints_fc, junction_fc, spatial_join,
            join_operation="JOIN_ONE_TO_ONE",
            match_option="WITHIN_A_DISTANCE",
            search_radius=f"{tolerance} Meters",
        )

        # 3. Endpoints with Join_Count = 0 are the disconnected ones.
        arcpy.management.MakeFeatureLayer(spatial_join, "unconnected_lyr", "Join_Count = 0")
        flagged = int(arcpy.management.GetCount("unconnected_lyr")[0])
        result["flagged"] = flagged

        if flagged == 0:
            logging.info("No disconnected edges detected. Topology integrity verified.")
            return result

        logging.warning("Identified %d disconnected edge endpoints.", flagged)
        arcpy.management.CopyFeatures("unconnected_lyr", "memory\\unconnected_flagged")

        # 4. Snap the flagged endpoints to the nearest junction within tolerance.
        snap_env = [[junction_fc, "VERTEX", f"{tolerance} Meters"]]
        arcpy.edit.Snap(edge_fc, snap_env)

        # 5. Rebuild connectivity associations for the corrected edges.
        arcpy.un.Associate(
            in_utility_network=gdb,
            association_type="CONNECTIVITY",
            from_feature=edge_fc,
            to_feature=junction_fc,
        )
        result["snapped"] = True
        logging.info("Applied spatial snap and rebuilt connectivity associations.")
        return result

    except arcpy.ExecuteError:
        logging.error("Geoprocessing failed: %s", arcpy.GetMessages(2))
        raise
    except Exception as exc:  # noqa: BLE001 — log then re-raise for the scheduler.
        logging.error("Unexpected error: %s", exc)
        raise
    finally:
        for temp_ds in (endpoints_fc, spatial_join):
            if arcpy.Exists(temp_ds):
                arcpy.management.Delete(temp_ds)


if __name__ == "__main__":
    outcome = repair_disconnected_edges()
    logging.info("Repair outcome: %s", outcome)

Geometric alignment is not topological validity. After the script runs, re-prove the result: call arcpy.un.ValidateTopology(gdb) across the affected tier, then run a Find Connected trace from each repaired junction. A trace that returns zero features or terminates early means the geometry snapped but the logical connection did not form — return to the connectivity-rule and LifecycleStatus checks above. These connected traces are the same primitives used by the upstream and downstream tracing algorithms that consume your repaired graph, so passing them here is the real acceptance test.

Production Deployment Pattern

To make this repeatable rather than a one-off rescue, embed the routine in the same governed pipeline that protects the rest of the network:

  • Run against an isolated version. Execute the repair in a dedicated named version, then reconcile and post after the re-validation trace passes. Never snap directly against DEFAULT while crews are editing.
  • Gate it in CI/CD. Wire the script into your validation pipeline so a pull request that touches edge feature classes runs the detect-and-trace check; fail the build if any endpoint stays at Join_Count = 0 or a connected trace returns zero features. This mirrors the gating approach in automating connectivity-rule validation in CI pipelines.
  • Add retry/backoff for locks. Enterprise geodatabases will occasionally reject ValidateTopology under a transient schema lock. Wrap the validate-and-repair call in a bounded exponential-backoff retry rather than failing the whole job.
  • Emit a structured delta report. Persist the flagged/snapped result plus the modified feature GlobalIDs to your CMMS or a REST endpoint so each automated repair produces a defensible audit record.
  • Schedule pre-commit checks. Run the tolerance and IsConnected = False checks before data promotion, blocking edits whose ConnectivityRuleID is null — catching the break at ingest, in line with the data ingestion pipelines for utility assets, is far cheaper than repairing it downstream.

For tool syntax and parameter validation, anchor your implementation to the official ArcGIS Pro Utility Network toolbox reference.

Conclusion

This procedure converts disconnected-edge repair from a manual editing chore into a deterministic, auditable pipeline: diagnose the schema and tolerance cause first, snap and re-associate within a confirmed tolerance, then prove integrity with a re-run connected trace. Automating it eliminates orphaned graph segments before they distort isolation planning, outage modeling, or regulatory reporting, and the structured delta report it emits satisfies asset-lifecycle audit requirements. Run it on an isolated version, gate it in CI/CD, and the same break stops recurring. The natural next step is to extend this gating across all topology errors via batch topology processing with Python.