Every SolidWorks API developer has spent hours debugging a macro that produces no error, no exception, and completely wrong output. The SolidWorks COM API is old enough that many of its failure modes predate modern error handling conventions — methods that silently return Nothing, boolean flags that are ignored, and side effects that modify document state without warning.

This is a catalogue of the seven most common ones. Each has a pattern, a root cause, and a fix.

1. SelectByID2: The Coordinate Space Trap

IModelDocExtension.SelectByID2 has two modes: name-based selection (pass the entity name as a string) and coordinate-based selection (pass "" as the name and provide X, Y, Z coordinates).

The coordinate mode is where most macros go wrong. The coordinates must be in model space, in meters — not screen pixels, not drawing units, not inches. If you pass coordinates in millimeters, SolidWorks silently selects the wrong entity or returns False with no message.

The second trap: coordinate-based selection uses the current view direction to project a pick ray. If the entity is hidden from the current view angle, selection fails silently.

' Wrong — coordinates in mm
swModel.Extension.SelectByID2 "", "FACE", 50, 30, 0, False, 0, Nothing, 0

' Correct — coordinates in meters
swModel.Extension.SelectByID2 "", "FACE", 0.05, 0.03, 0, False, 0, Nothing, 0

For name-based selection, the entity name must include the configuration prefix for components in an assembly (ComponentName-1@AssemblyName). Recording a macro captures the name at recording time — if you rename a component or add a second instance, the hardcoded name breaks silently.

The reliable pattern for faces and edges is to traverse the topology directly via IBody2.GetFaces or IFeature.GetFaces and select via IEntity.Select4 rather than relying on SelectByID2 with coordinates.

2. Lightweight Components: GetModelDoc2 Returns Nothing

When a SolidWorks assembly opens in lightweight mode (the default for large assemblies), IComponent2.GetModelDoc2 returns Nothing. The component exists in the assembly tree, the reference path resolves, but the model document is not loaded into memory.

Dim swComp As SldWorks.Component2
Dim swRefModel As SldWorks.ModelDoc2

swRefModel = swComp.GetModelDoc2  ' Returns Nothing for lightweight components
swRefModel.GetTitle  ' Crashes here — NullReferenceException

The macro records no error on the GetModelDoc2 call. The crash happens one line later when you try to use the reference, and the stack trace points to the wrong place.

Fix — resolve before accessing:

' Option 1: resolve the specific component
If swComp.GetSuppression = swComponentSuppressedState_e.swComponentLightweight Then
    swComp.SetComponentState swComponentSuppressedState_e.swComponentResolved
End If

' Option 2: resolve all lightweight components in the assembly at once
Dim swAssy As SldWorks.AssemblyDoc
swAssy.ResolveAllLightWeightComponents True

' Option 3: guard with null check
swRefModel = swComp.GetModelDoc2
If Not swRefModel Is Nothing Then
    ' safe to use
End If

For batch automation that processes every component in an assembly, call ResolveAllLightWeightComponents at the start of the macro before any traversal. The performance cost is real for large assemblies — but it’s better than silently skipping parts. See the in-process vs standalone API trade-offs for context on when to resolve vs when to use component metadata directly.

3. CreateLine With Vertical Geometry at the Origin

ISketchManager.CreateLine creates a sketch line and returns an ISketchSegment. What it does not tell you: when you create a line with both endpoints on the Y-axis (x1=0, x2=0), SolidWorks automatically adds a Vertical sketch relation. If the start point is at the sketch origin (0,0,0), SolidWorks also adds a Coincident relation to the origin point.

These implicit relations are added silently. If your subsequent code adds another coincident or fix relation to the same point, the sketch goes over-defined — but your macro gets no error. The sketch just rebuilds with error markers, and any downstream feature operation on that sketch may produce unexpected geometry or fail silently.

' This creates a vertical line from origin to (0, 0.1, 0)
' SW silently adds: Vertical + Coincident-to-origin
Dim swSkSeg As SldWorks.SketchSegment
swSkSeg = swSkMgr.CreateLine(0, 0, 0, 0, 0.1, 0)

' If you then do this, the sketch is over-defined:
swModel.Extension.SelectByID2 "Point1@Sketch1", "SKETCHPOINT", 0, 0, 0, False, 0, Nothing, 0
swSkMgr.CreateCoincidentRelation swSkPoint, swOriginPoint  ' duplicate — no error thrown

Fix: After creating lines, check ISketchManager.ActiveSketch.GetSketchContours and verify the sketch is not over-defined before closing it. Alternatively, avoid placing line endpoints exactly on the origin — offset by a small amount and add the coincident relation explicitly so it appears in the relations list.

4. FeatureExtrusion3 With Multi-Contour Sketches

IFeatureManager.FeatureExtrusion3 operates on the active sketch. When that sketch contains multiple closed loops — an outer boundary and one or more inner holes — the method picks the outermost contour by default and ignores the inner loops. For an annular profile (a ring), this produces a solid disc instead of the intended hollow extrusion.

No error is returned. The feature is created successfully. It just has the wrong shape.

' Sketch has outer rectangle + inner circle = annular profile
' FeatureExtrusion3 produces solid rectangle extrusion, not annular boss
swFeat = swFeatMgr.FeatureExtrusion3(True, False, False, _
    swEndConditions_e.swEndCondBlind, 0, 0.01, 0, _
    False, False, False, False, 0, 0, False, False, False, False, True, True, True, _
    swStartConditions_e.swStartSketchPlane, 0, False)

Fix: Before calling FeatureExtrusion3, select the specific contour you want to extrude using SelectByID2 with type "SKETCHCONTOUR". SolidWorks then uses the selected contour rather than auto-picking.

' Select the outer contour first
swModel.Extension.SelectByID2 "Sketch1", "SKETCHCONTOUR", x, y, z, False, 0, Nothing, 0
' Now FeatureExtrusion3 operates on the selected contour

For complex multi-contour logic, FeatureBossExtrude3 (added in SolidWorks 2012) provides explicit contour selection parameters and is preferred over the older FeatureExtrusion3. If you’re writing new automation code, use FeatureBossExtrude3 or FeatureCut5 directly.

5. SetSelectionMark Is a No-Op in Modern SolidWorks

Older SolidWorks macro recordings and forum examples often call IModelDoc2.SetSelectionMark or IModelDocExtension.SetSelectionMark to assign a selection mark integer before making a selection. This was used to differentiate selections for operations that require multiple inputs (like IFeatureManager.FeatureRevolve2 which needs the profile and the axis in separate selection sets).

SetSelectionMark was deprecated in SolidWorks 2014. In SolidWorks 2019+, calling it produces no error but also has no effect. The selection mark is simply not applied, and the subsequent feature operation reads zero-marked selections, fails silently, or picks the wrong entities.

Fix: Pass the mark integer directly to SelectByID2’s Mark parameter (the 9th parameter, an integer):

' Deprecated approach — no effect in modern SW
swModel.Extension.SetSelectionMark 1
swModel.Extension.SelectByID2 "Sketch1", "SKETCH", 0, 0, 0, False, 0, Nothing, 0
swModel.Extension.SetSelectionMark 4
swModel.Extension.SelectByID2 "Line1@Sketch1", "SKETCHSEGMENT", x, y, z, False, 0, Nothing, 0

' Correct approach — pass mark in SelectByID2 directly
swModel.Extension.SelectByID2 "Sketch1", "SKETCH", 0, 0, 0, False, 1, Nothing, 0
swModel.Extension.SelectByID2 "Line1@Sketch1", "SKETCHSEGMENT", x, y, z, True, 4, Nothing, 0

Note the True for the Append parameter on the second call — this adds to the selection rather than replacing it.

6. GetModelDoc2 Returns Nothing for Documents Not Open in Session

IComponent2.GetModelDoc2 returns Nothing not only for lightweight components (gotcha #2), but also when the component’s reference file is not currently open in the SolidWorks session at all. This happens most often in automation scripts that open assemblies via ISldWorks.OpenDoc6 with suppressed or excluded component states.

' Component file is on disk but not loaded in SW session
swRefModel = swComp.GetModelDoc2  ' Nothing — file not open

The distinction matters because the fix is different. For lightweight components, ResolveAllLightWeightComponents loads them. For unloaded documents, you need to call ISldWorks.OpenDoc6 explicitly with the component’s path:

Dim compPath As String
compPath = swComp.GetPathName  ' Get the file path

If swComp.GetModelDoc2 Is Nothing Then
    Dim errors As Long, warnings As Long
    swModel = swApp.OpenDoc6(compPath, swDocumentTypes_e.swDocPART, _
        swOpenDocOptions_e.swOpenDocOptions_Silent, "", errors, warnings)
End If

For batch DXF export workflows that traverse large assemblies, the cost of opening every component sequentially is significant. The practical approach is to open the top-level assembly with swOpenDocOptions_e.swOpenDocOptions_LoadModel to force all referenced components to load, then traverse.

7. VBA Custom Property Access Marks the Document Dirty

This one costs teams hours of debugging. When a VBA macro reads custom properties via IModelDoc2.Extension.CustomPropertyManager, SolidWorks marks the document as modified — even if you only read values and write nothing.

The mechanism: ICustomPropertyManager.Get5 (the read method) internally queries the property store and in some SolidWorks versions (2020–2024 depending on the service pack) leaves the document in a modified state. The user sees a “save?” dialog on close. In automated pipelines, this causes silent document locks.

Dim custPropMgr As SldWorks.CustomPropertyManager
custPropMgr = swModel.Extension.CustomPropertyManager("")

Dim valOut As String, valResolved As String
Dim wasResolved As Boolean
' This read operation can mark the document dirty in certain SW builds
custPropMgr.Get5 "Material", False, valOut, valResolved, wasResolved

Fix 1: After reading properties, explicitly reset the dirty flag:

swModel.SetSaveFlag  ' Resets the dirty state without saving

Wait — SetSaveFlag in SolidWorks marks the document as needing a save, not clears it. The correct method is IModelDoc2.ClearDocumentDirty:

' After reading custom properties
swModel.ClearDocumentDirty  ' Clears the modified flag

Fix 2: Open the document with swOpenDocOptions_e.swOpenDocOptions_ReadOnly flag. Read-only documents can’t be marked dirty in the UI, and your reads won’t trigger save prompts.

Fix 3: Avoid CustomPropertyManager for bulk reads. Use IModelDoc2.GetCustomInfoNames and GetCustomInfo2 instead — these are the older COM-style accessors that bypass the newer property store and are less likely to trigger the dirty flag in affected builds.

This problem also manifests when accessing IModelDoc2.Extension.get_CustomPropertyManager repeatedly in a loop. If you’re processing hundreds of parts in a session, the accumulated dirty-flag writes can slow the session noticeably as SolidWorks queues internal change notifications.


The Common Thread

Most of these failures share a pattern: the SolidWorks API is a COM wrapper around a 1995-era internal architecture. Methods return Nothing or False instead of throwing exceptions. Side effects like the dirty flag are undocumented. Deprecated methods are silently no-ops rather than raising errors.

The defensive coding habits that help:

  • Always null-check COM return values before using them
  • Never trust a False return without logging what entity name or coordinate was passed
  • Run the SolidWorks API debugger (SW Macro → Tools → References) to verify you’re using the correct interop version for your SW release
  • For any macro that runs in batch, test against assemblies with lightweight components, suppressed components, and externally referenced parts

If you’re moving from VBA macros to C# add-ins, many of these gotchas carry over — but the meters trap in VBA macros becomes less of an issue once you’re in strongly-typed C# where unit mismatches produce compiler errors rather than silent wrong values. The in-process COM add-in architecture also gives you access to assembly events that let you react to component state changes rather than polling — making the lightweight component problem tractable in real-time workflows. The same silent failure patterns extend to export — particularly STEP export, where the underlying kernel serialisation determines whether the receiving system can reconstruct your geometry faithfully or gets a NURBS approximation instead.

CadShift handles most of these cases internally — assembly traversal with lightweight resolution, null component guards, and clean document state after export. If you’re building automation that doesn’t need the full depth of the API, that avoidance of these failure modes is worth something.