Repository: fonttools/fonttools

Issue:
[varLib.merger] <exception str() failed>
I'm in the process of figuring out what is happening here, but in the meantime I thought I'd post this as it apears there is a bug in the exception handling: see the `<exception str() failed>` messages below.

```
Traceback (most recent call last):
  File "/opt/hostedtoolcache/Python/3.8.13/x64/lib/python3.8/site-packages/fontmake/font_project.py", line 1065, in run_from_designspace
    self._run_from_designspace_interpolatable(
  File "/opt/hostedtoolcache/Python/3.8.13/x64/lib/python3.8/site-packages/fontmake/font_project.py", line 1157, in _run_from_designspace_interpolatable
    self.build_variable_fonts(
  File "/opt/hostedtoolcache/Python/3.8.13/x64/lib/python3.8/site-packages/fontmake/font_project.py", line 384, in build_variable_fonts
    fonts = ufo2ft.compileVariableTTFs(
  File "/opt/hostedtoolcache/Python/3.8.13/x64/lib/python3.8/site-packages/ufo2ft/__init__.py", line 605, in compileVariableTTFs
    vfNameToTTFont = varLib.build_many(
  File "/opt/hostedtoolcache/Python/3.8.13/x64/lib/python3.8/site-packages/fontTools/varLib/__init__.py", line 911, in build_many
    vf = build(
  File "/opt/hostedtoolcache/Python/3.8.13/x64/lib/python3.8/site-packages/fontTools/varLib/__init__.py", line 986, in build
    _merge_OTL(vf, model, master_fonts, axisTags)
  File "/opt/hostedtoolcache/Python/3.8.13/x64/lib/python3.8/site-packages/fontTools/varLib/__init__.py", line 624, in _merge_OTL
    merger.mergeTables(font, master_fonts, ['GSUB', 'GDEF', 'GPOS'])
  File "/opt/hostedtoolcache/Python/3.8.13/x64/lib/python3.8/site-packages/fontTools/varLib/merger.py", line 150, in mergeTables
    self.mergeThings(font[tag], [m.get(tag) for m in master_ttfs])
  File "/opt/hostedtoolcache/Python/3.8.13/x64/lib/python3.8/site-packages/fontTools/varLib/merger.py", line 1067, in mergeThings
    super(VariationMerger, self).mergeThings(out, lst)
  File "/opt/hostedtoolcache/Python/3.8.13/x64/lib/python3.8/site-packages/fontTools/varLib/merger.py", line 138, in mergeThings
    self.mergeObjects(out, lst)
  File "/opt/hostedtoolcache/Python/3.8.13/x64/lib/python3.8/site-packages/fontTools/varLib/merger.py", line 108, in mergeObjects
    mergerFunc(self, value, values)
  File "/opt/hostedtoolcache/Python/3.8.13/x64/lib/python3.8/site-packages/fontTools/varLib/merger.py", line 1067, in mergeThings
    super(VariationMerger, self).mergeThings(out, lst)
  File "/opt/hostedtoolcache/Python/3.8.13/x64/lib/python3.8/site-packages/fontTools/varLib/merger.py", line 138, in mergeThings
    self.mergeObjects(out, lst)
  File "/opt/hostedtoolcache/Python/3.8.13/x64/lib/python3.8/site-packages/fontTools/varLib/merger.py", line 108, in mergeObjects
    mergerFunc(self, value, values)
  File "/opt/hostedtoolcache/Python/3.8.13/x64/lib/python3.8/site-packages/fontTools/varLib/merger.py", line 1067, in mergeThings
    super(VariationMerger, self).mergeThings(out, lst)
  File "/opt/hostedtoolcache/Python/3.8.13/x64/lib/python3.8/site-packages/fontTools/varLib/merger.py", line 138, in mergeThings
    self.mergeObjects(out, lst)
  File "/opt/hostedtoolcache/Python/3.8.13/x64/lib/python3.8/site-packages/fontTools/varLib/merger.py", line 108, in mergeObjects
    mergerFunc(self, value, values)
  File "/opt/hostedtoolcache/Python/3.8.13/x64/lib/python3.8/site-packages/fontTools/varLib/merger.py", line 1067, in mergeThings
    super(VariationMerger, self).mergeThings(out, lst)
  File "/opt/hostedtoolcache/Python/3.8.13/x64/lib/python3.8/site-packages/fontTools/varLib/merger.py", line 143, in mergeThings
    raise ShouldBeConstant(self, expected=out, got=lst)
fontTools.varLib.errors.ShouldBeConstant: <exception str() failed>
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
  File "/opt/hostedtoolcache/Python/3.8.13/x64/lib/python3.8/site-packages/fontmake/__main__.py", line 639, in main
    project.run_from_designspace(inputs.designspace_path, **args)
  File "/opt/hostedtoolcache/Python/3.8.13/x64/lib/python3.8/site-packages/fontmake/font_project.py", line 1080, in run_from_designspace
    raise FontmakeError(
fontmake.errors.FontmakeError: <exception str() failed>
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
  File "/opt/hostedtoolcache/Python/3.8.13/x64/bin/fontmake", line 8, in <module>
    sys.exit(main())
  File "/opt/hostedtoolcache/Python/3.8.13/x64/lib/python3.8/site-packages/fontmake/__main__.py", line 664, in main
    sys.exit(f"fontmake: Error: {str(e)}")
  File "/opt/hostedtoolcache/Python/3.8.13/x64/lib/python3.8/site-packages/fontmake/errors.py", line 33, in __str__
    cause = str(self.__cause__) if self.__cause__ is not None else None
  File "/opt/hostedtoolcache/Python/3.8.13/x64/lib/python3.8/site-packages/fontTools/varLib/errors.py", line 70, in __str__
    return "\n\n" + basic + location + self.details
  File "/opt/hostedtoolcache/Python/3.8.13/x64/lib/python3.8/site-packages/fontTools/varLib/errors.py", line 86, in details
    good_ttf = next(
StopIteration
```


Discussion:
Ah, it's the `StopIteration` at the end that's causing the `<exception str() failed>` message. `ShouldBeConstant.details` is failing, and we're not getting a useful error message at all.

Resolving patch:
diff --git a/Lib/fontTools/varLib/errors.py b/Lib/fontTools/varLib/errors.py
--- a/Lib/fontTools/varLib/errors.py
+++ b/Lib/fontTools/varLib/errors.py
@@ -86,7 +86,9 @@ def details(self):
         good_ttf = next(
             ttf
             for ttf in self.merger.ttfs
-            if ttf["GPOS"].table.FeatureList.FeatureCount == self.cause["expected"]
+            if self.stack[-1] in ttf
+            and ttf[self.stack[-1]].table.FeatureList.FeatureCount
+            == self.cause["expected"]
         )
 
         good_features = [


Test patch: