`SketchUp::require(path)` is broken on case-sensitive APFS

I reported this through Trimble Support, but I figured I’d cross-post it here.


I use SketchUp on a Mac with a case-sensitive filesystem.

When loading extensions, at some point in the process the path of the extension has all uppercase characters forcibly converted to lowercase characters.

As best I can tell, this bug is somewhere in the implementation of the SketchUp::require(path) method, as the bug traces through extensions.rb Line 197.

This is the Ruby console output I am seeing:

#<Errno::ENOENT: No such file or directory @ rb_sysopen - /users/elsiehupp/library/application support/sketchup 2025/sketchup/plugins/habitat_site_context/Resources/en-US.json>
/users/elsiehupp/library/application support/sketchup 2025/sketchup/plugins/habitat_site_context/localise.rbe:26:in `read'
/users/elsiehupp/library/application support/sketchup 2025/sketchup/plugins/habitat_site_context/localise.rbe:26:in `initialize'
/Users/elsiehupp/Library/Application Support/SketchUp 2025/SketchUp/Plugins/habitat_site_context.rb:9:in `new'
/Users/elsiehupp/Library/Application Support/SketchUp 2025/SketchUp/Plugins/habitat_site_context.rb:9:in `<module:HabitatSiteContext>'
/Users/elsiehupp/Library/Application Support/SketchUp 2025/SketchUp/Plugins/habitat_site_context.rb:4:in `<top (required)>'
#<Errno::ENOENT: No such file or directory @ dir_s_mkdir - /users/elsiehupp/library/application support/sketchup 2025/sketchup/plugins/su_diffusion/current_lib>
/users/elsiehupp/library/application support/sketchup 2025/sketchup/plugins/su_diffusion/su_loader.rbe:21:in `mkdir'
/users/elsiehupp/library/application support/sketchup 2025/sketchup/plugins/su_diffusion/su_loader.rbe:21:in `<module:SketchUpDiffusion>'
/users/elsiehupp/library/application support/sketchup 2025/sketchup/plugins/su_diffusion/su_loader.rbe:1:in `<main>'
/Applications/SketchUp 2025/SketchUp.app/Contents/Resources/Tools/extensions.rb:197:in `eval'
/Applications/SketchUp 2025/SketchUp.app/Contents/Resources/Tools/extensions.rb:197:in `require'
/Applications/SketchUp 2025/SketchUp.app/Contents/Resources/Tools/extensions.rb:197:in `load'
/Users/elsiehupp/Library/Application Support/SketchUp 2025/SketchUp/Plugins/su_diffusion.rb:22:in `register_extension'
/Users/elsiehupp/Library/Application Support/SketchUp 2025/SketchUp/Plugins/su_diffusion.rb:22:in `<module:SketchUpDiffusion>'
/Users/elsiehupp/Library/Application Support/SketchUp 2025/SketchUp/Plugins/su_diffusion.rb:5:in `<top (required)>'
#<Errno::ENOENT: No such file or directory @ rb_sysopen - >
/users/elsiehupp/library/application support/sketchup 2025/sketchup/plugins/su_sandbox/geometryhelpers.rbe:107:in `initialize'
/users/elsiehupp/library/application support/sketchup 2025/sketchup/plugins/su_sandbox/geometryhelpers.rbe:107:in `open'
/users/elsiehupp/library/application support/sketchup 2025/sketchup/plugins/su_sandbox/geometryhelpers.rbe:107:in `ReadValues'
/users/elsiehupp/library/application support/sketchup 2025/sketchup/plugins/su_sandbox/geometryhelpers.rbe:45:in `initialize'
/users/elsiehupp/library/application support/sketchup 2025/sketchup/plugins/su_sandbox/sandboxmenus.rbe:33:in `new'
/users/elsiehupp/library/application support/sketchup 2025/sketchup/plugins/su_sandbox/sandboxmenus.rbe:33:in `<module:SandboxTools>'
/users/elsiehupp/library/application support/sketchup 2025/sketchup/plugins/su_sandbox/sandboxmenus.rbe:24:in `<main>'
/Applications/SketchUp 2025/SketchUp.app/Contents/Resources/Tools/extensions.rb:197:in `eval'
/Applications/SketchUp 2025/SketchUp.app/Contents/Resources/Tools/extensions.rb:197:in `require'
/Applications/SketchUp 2025/SketchUp.app/Contents/Resources/Tools/extensions.rb:197:in `load'
/Users/elsiehupp/Library/Application Support/SketchUp 2025/SketchUp/Plugins/su_sandbox.rb:50:in `register_extension'
/Users/elsiehupp/Library/Application Support/SketchUp 2025/SketchUp/Plugins/su_sandbox.rb:50:in `<module:SandboxTools>'
/Users/elsiehupp/Library/Application Support/SketchUp 2025/SketchUp/Plugins/su_sandbox.rb:29:in `<top (required)>'
#<LoadError: cannot load such file -- LangHandler.rb>
<internal:/Applications/SketchUp 2025/SketchUp.app/Contents/Frameworks/Ruby.framework/Versions/3.2.2/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:85:in `require'
<internal:/Applications/SketchUp 2025/SketchUp.app/Contents/Frameworks/Ruby.framework/Versions/3.2.2/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:85:in `require'
/Users/elsiehupp/Library/Application Support/SketchUp 2025/SketchUp/Plugins/su_shadowstringsfix/shadowstringsfix_loader.rb:14:in `<top (required)>'
/Applications/SketchUp 2025/SketchUp.app/Contents/Resources/Tools/extensions.rb:197:in `require'
/Applications/SketchUp 2025/SketchUp.app/Contents/Resources/Tools/extensions.rb:197:in `load'
/Users/elsiehupp/Library/Application Support/SketchUp 2025/SketchUp/Plugins/su_shadowstringsfix.rb:39:in `register_extension'
/Users/elsiehupp/Library/Application Support/SketchUp 2025/SketchUp/Plugins/su_shadowstringsfix.rb:39:in `<module:ShadowStringsFix>'
/Users/elsiehupp/Library/Application Support/SketchUp 2025/SketchUp/Plugins/su_shadowstringsfix.rb:20:in `<top (required)>'

Note where, e.g., /Users/elsiehupp/Library/Application Support/SketchUp 2025 turns into /users/elsiehupp/library/application support/sketchup 2025.

Steam (the video game service) stupidly also does not support case-sensitive filesystems on macOS, and the known workaround is to create a sparsebundle (or APFS volume) with a case-insensitive filesystem, automount the sparsebundle (or APFS volume) at system startup, and symlink ~/Library/Steam to said mounted sparsebundle (or APFS volume).

A similar workaround could probably work with SketchUp; the path that gets fed into SketchUp::require(path) ultimately starts in each extension loader script’s __FILE__, so if the extensions are symlinked to a case-insensitive filesystem the loader should work.

Well, I tried that with /Users/elsiehupp/Library/Application Support/SketchUp 2025, and SketchUp freaked out and crashed on launch.

So I tried just symlinking /Users/elsiehupp/Library/Application Support/SketchUp 2025/SketchUp/Plugins, and lo and behold it worked!~

Which I guess is to say the problem apparently is indeed a bug with SketchUp::require(path) not working properly on case-sensitive filesystems, ~and symlinking just the Plugins directory to a case-insensitive APFS volume is an available workaround.

(It would still be nice if Trimble fixed this bug, though.)

EDIT: Actually, no, the workaround didn’t work. SketchUp just doesn’t see the symlinked Plugins directory, so none of the plugins fail to load… because SketchUp doesn’t even try to load them.

EDIT 2: Actually, yes, it does work, but only if you create a symlink in the terminal using, e.g.:

mv ~/Library/Application Support/SketchUp 2025/SketchUp/Plugins /Volumes/SketchUp/Plugins
ln -s /Volumes/SketchUp/Plugins ~/Library/Application Support/SketchUp 2025/SketchUp/Plugins

My mistake was being lazy and creating an “alias” in the Finder, which apparently isn’t the same thing as a symlink.

Edit 3: With the symlink to the Plugins folder, SketchUp doesn’t try to load extensions, but the Extension Manager still sees them and thinks they’ve been loaded. So maybe using a proper symlink (i.e. not a Finder alias) with the entire ~/Library/Application Support/SketchUp 2025 folder might work. I’m tired, so I’ll try this later.

I should add: the Apple KB article on APFS volumes.

(The sparsebundle approach is probably more applicable for deployment environments; for instance, the Plugins folder could be a read-only .dmg file rather than a writeable sparsebundle.)

Correct. This is by design. It is not actually a bug. Sketchup::require downcases the path when it pushes it into the $LOADED_FEATURES (aka $") array.

This was done (in hopes) of not doing what Kernel#require does on a case-insensitive filesystem when mixed case filenames are passed. For example, arguments "sketchup.rb", "Sketchup.rb" and "SKETCHUP.rb" each load or reload the "Tools/sketchup.rb" file because the Kernel#require method is doing case-sensitive string comparisons against the members of the $" array.

I sort of feel that the API should have overridden the Kernel#require method to fix the issue there for case-insensitive filesystems.
ADD: This later got more complicated when SketchUp began pseudo-supporting RubyGems which further overrides the global require method.

AFAIK (relying upon memory,) the API is not supported for running on case-sensitive OS installations. I would surmise that you’d be a long time in waiting for a solution to this particular scenario.


@TedVitale_SU | @CraigTrickett

  • Can the System Requirements Support page and the API documentation pages be updated to address case-sensitive installations for the Mac editions, please?
1 Like

The easiest possible fixes, I would think is to:

  1. Add a hash (named) argument to Sketchup::require to control the the downcasing of paths. The API should determine the OS filesystem’s case sensitivity and set the default Boolean value for this extra argument accordingly.
    An API coder could explicitly override the default when necessary.

  2. This setting could (also) be exposed as an application level Boolean property at Sketchup::case_senstive? and Sketchup::case_senstive= which could allow coders to temporarily change the behavior during loading their code.