Can't install native extension gem which includes pre-build binaries
Describe the bug
Can't install native extension gem which includes pre-build binaries
e.g.
- https://rubygems.org/gems/ffi v1.17.0+
- https://rubygems.org/gems/google-protobuf v4.31.0+
Additional context How are you using GCP buildpacks?
- [ ]
packand thegcr.io/buildpacks/builder - [x] Cloud Functions
- [ ] Cloud Run
- [ ] Cloud Build
- [ ] App Engine Standard
- [ ] App Engine Flex
- [ ] Firebase App Hosting
Did this used to work? yes
What language is your project primarily written in? Ruby 3.3
Steps To Reproduce Gemfile
source "https://rubygems.org"
gem "functions_framework", "1.6.0"
gem "ffi", "1.17.0"
Steps to reproduce the behavior:
- Deploy using
gcloud functions deploycommand- e.g.
gcloud functions deploy my-func --gen2 --runtime=ruby33
- e.g.
Expected behavior
Deploy is successful
Actual behavior
Error in buildpack
Cloud Build log
ERROR: (gcloud.beta.functions.deploy) OperationError: code=3, message=Build failed with status: FAILURE and message: Fetching gem metadata from https://rubygems.org/...........
Your bundle is locked to ffi (1.17.0-x86_64-linux) from rubygems repository
https://rubygems.org/ or installed locally, but that version can no longer be
found in that source. That means the author of ffi (1.17.0-x86_64-linux) has
removed it. You'll need to update your bundle to a version other than ffi
(1.17.0-x86_64-linux) that hasn't been removed in order to install.. For more details see the logs at https://console.cloud.google.com/cloud-build/builds;xxxxxxxxxxxxxxxxxx
Why?
Since ffi v1.17.0, ffi gem includes pre-build binaries in the following format.
-
ffi-${GEM_VERSION}-x86_64-linux-gnu.gem -
ffi-${GEM_VERSION}-x86_64-linux-musl.gem - ....
c.f. https://rubygems.org/gems/ffi/versions/1.17.0-x86_64-linux-gnu
So it seems that bundler is trying to download 1.17.0-x86_64-linux.gem (instead of 1.17.0-x86_64-linux-gnu.gem) and is getting an error.
bundle lock --add-platform x86_64-linux is executed before bundle install.
https://github.com/GoogleCloudPlatform/buildpacks/blob/3dea9e987f9424a08ad455610431126147d84c7e/cmd/ruby/bundle/main.go#L123
About gem other than ffi
This issue covers ffi, but I have observed the same problem in other google-protobuf v4.31.0+
https://rubygems.org/gems/google-protobuf/versions/4.31.0-x86-linux-gnu
Since I expect that there will be more such gems in the future, I think it is better to use buildpack instead of each gem.
Workaround 1: Use old version
e.g.
# Gemfile
gem "ffi", "< 1.17.0"
This would be fine for a temporary period.
However, new features are not available or security issues remain by continuing to use older versions
Workaround 2: Pass BUNDLE_FORCE_RUBY_PLATFORM to --set-build-env-vars
e.g.
gcloud functions deploy my-func --gen2 --runtime=ruby33 \
--set-build-env-vars=BUNDLE_FORCE_RUBY_PLATFORM=1
This means building all native extensions in Gemfile. This is very slow!
For example, https://rubygems.org/gems/grpc takes 30+ minutes to build, so Cloud Build will give a timeout error when deploying
Running "bundle install (NOKOGIRI_USE_SYSTEM_LIBRARIES=1 MALLOC_ARENA_MAX=2 LANG=C.utf8)"
--
274 | Fetching gem metadata from https://rubygems.org/
(...)
Fetching grpc 1.70.0
Installing grpc 1.70.0 with native extensions
TIMEOUT
ERROR: context deadline exceeded
Workaround 3. Use force_ruby_platform in Gemfile
By using force_ruby_platform , only certain gems can be built at bundle install time without using the pre-build gem.
e.g.
# Gemfile
gem "ffi", force_ruby_platform: true
However, version of bundler used in buildpack is out of date, so I get an error...
ERROR: (gcloud.beta.functions.deploy) OperationError: code=3, message=Build failed with status: FAILURE and message: [!] There was an error parsing `Gemfile`: You passed :force_ruby_platform as an option for gem 'ffi', but it is invalid. Valid options are: group, groups, git, path, glob, name, branch, ref, tag, require, submodules, platform, platforms, type, source, install_if, gemfile, github, gist, bitbucket. You may be able to resolve this by upgrading Bundler to the newest version.. Bundler cannot continue.
# from /workspace/Gemfile:25
# -------------------------------------------
> gem "ffi", force_ruby_platform: true
# -------------------------------------------.
force_ruby_platform is available since bunlder v2.3.18+
https://github.com/rubygems/rubygems/releases/tag/bundler-v2.3.18
But buidpack seems to be using bundler v2.3.15
https://github.com/GoogleCloudPlatform/buildpacks/blob/e3a8f6ac1f2eadb97379e93e84d577545cea9d83/cmd/ruby/rubygems/main.go#L37
The problem is that the default and locked Bundler version (2.3.15) included with the buildpack doesn't recognize newer Linux platform variants like linux-musl and linux-gnu. Gems targeting *-linux-gnu or *-linux-musl require at least RubyGems 3.3.22 and Bundler 2.3.21 to install properly. One workaround is to compile these gems from source.
As for your second workaround, you can extend the timeout like this:
gcloud functions deploy my-func \
--gen2 \
--runtime ruby33 \
--entry-point my_func \
--region us-central1 \
--source . \
--trigger-http \
--allow-unauthenticated \
--timeout 3600 \
--set-build-env-vars BUNDLE_FORCE_RUBY_PLATFORM=1
It would be nice if buildpacks allowed overriding the Bundler version.
@pjmartorell
As for your second workaround, you can extend the timeout like this:
No, --timeout is timeout for function that is already deployed, not timeout for deploying.
https://cloud.google.com/sdk/gcloud/reference/functions/deploy#--timeout
@pjmartorell
As for your second workaround, you can extend the timeout like this:
No,
--timeoutis timeout for function that is already deployed, not timeout for deploying.https://cloud.google.com/sdk/gcloud/reference/functions/deploy#--timeout
True, sorry for the confusion 👍🏻
We have upgraded the bundler version to 2.3.21 in https://github.com/GoogleCloudPlatform/buildpacks/commit/6e396f2db7a79b1c40e246a71fbdb2115ef4104c.
The buildpacks now fully support the force_ruby_platform option and can correctly handle gems with platform variants like linux-musl and linux-gnu. The prod release of the builder will complete next week.
Thanks for bringing this issue to our attention and providing such a detailed analysis!
We have upgraded the bundler version to
2.3.21in 6e396f2.The buildpacks now fully support the
force_ruby_platformoption and can correctly handle gems with platform variants likelinux-muslandlinux-gnu. The prod release of the builder will complete next week.Thanks for bringing this issue to our attention and providing such a detailed analysis!
Thanks for upgrading the bundler version! 🙌 I gave it a try using the latest builder (universal_builder_20250819_RC00), but it’s still installing bundler 2.3.15 instead of 2.3.21.
Am I missing something here? Could this be because the updated builder hasn’t been released yet?
See the logs:
===> DETECTING
| target distro name/version labels not found, reading /etc/os-release file
| 5 of 7 buildpacks participating
| google.ruby.runtime 0.0.1
| google.ruby.rubygems 0.9.0
| google.ruby.bundle 0.9.0
| google.config.entrypoint 0.9.0
| google.utils.label-image 0.0.2
| ===> RESTORING
| ===> BUILDING
| target distro name/version labels not found, reading /etc/os-release file
| === Ruby - Runtime ([email protected]) ===
| Setting Nodejs runtime version GOOGLE_NODEJS_VERSION: *
| ***** CACHE MISS: "ruby"
| Installing Ruby Runtime v3.4.5.
| 2025/08/28 11:51:16 [DEBUG] GET https://dl.google.com/runtimes/ubuntu2204/ruby/ruby-3.4.5.tar.gz
| Removing 'tmp' and 'log' directories in user code
| === Ruby - Rubygems ([email protected]) ===
| 2025/08/28 11:51:18 [DEBUG] GET https://rubygems.org/rubygems/rubygems-3.3.15.tgz
| --------------------------------------------------------------------------------
| Running "ruby setup.rb -E --no-document --destdir /layers/google.ruby.rubygems/rubygems --prefix /"
| Successfully built RubyGem
| Name: bundler
| Version: 2.3.15
| File: bundler-2.3.15.gem
| Bundler 2.3.15 installed
| RubyGems 3.3.15 installed
| Regenerating binstubs
| Regenerating plugins
We had to rollback the bundler upgrade change because it caused backward-incompatible issues So native extensions are still not supported 😔. We plan to upgrade bundler with the next Ruby 3.5 runtime release.