Skip to content

postgresql_user / postgresql_database fail under Chef 19 (Habitat) #833

Closed

Description

@Neopixler

When running Chef 19 packaged as a Habitat package, the postgresql_user and postgresql_database resources fail with:

FATAL: LoadError: pg's C extension failed to load:
  cannot load such file -- 3.4/pg_ext
  libpq.so.5: cannot open shared object file: No such file or directory - /hab/pkgs/core/ruby3_4/3.4.8/.../gems/pg-1.6.3/lib/pg_ext.so

Root Cause

Since v11.0.0, this cookbook installs the pg gem to back postgresql_user and postgresql_database. The native extension pg_ext.so links against libpq.so.5 at runtime.

Habitat packages Chef with library isolation: the Ruby process is started with a scoped LD_LIBRARY_PATH pointing only to Habitat-internal paths, and the binary appears to be compiled with -z nodefaultlib, which disables both the ldconfig cache and default system library paths (/lib, /usr/lib). System-installed libpq.so.5 (from libpq5) is therefore invisible to the dynamic linker even when correctly installed.

Setting ENV['LDFLAGS'] or ENV['DLDFLAGS'] before the gem builds does not help:

  • LDFLAGS controls executable linking in mkmf, not .so linking.
  • DLDFLAGS is initialised by mkmf from RbConfig::CONFIG, not from ENV.

Adding system paths to LD_LIBRARY_PATH causes a crash (__nptl_change_stack_perm symbol error) because the system libc.so.6 gets loaded alongside Habitat's own bundled libc.

Environment

  • OS: Ubuntu 24.04 (noble)
  • Chef version: 19.3.15 (Habitat)
  • sous-chefs/postgresql: 13.0.5 (reproduced on all v11+ versions)
  • PostgreSQL: 16 (PGDG)

Workaround

Downgrade to Chef 18 (Omnibus). Omnibus uses the system linker and resolves system libraries normally — the issue does not occur.

Activity

  1. damacus commented on Aug 11, 2026

    @damacus
    Member

    I've got a partial fix here, but you are better off leveraging your Progress Support contract here.

    Given we're debugging Habitat issues I cannot guarantee any fix that lands can actually work.

  2. added
    Upstream BugBug in upstream vendor application
    chef-19Issues specific to Chef Infra Client 19
    habitatIssues specific to Chef Habitat packaging or runtime
    waitingWaiting on an external dependency or vendor response
    on Aug 11, 2026
  3. damacus commented on Aug 11, 2026

    @damacus
    Member

    Thanks for the detailed report. We have confirmed that this is specific to the Chef 19 Habitat runtime, but this repository cannot install or exercise that runtime in CI. A cookbook workaround for native pg packaging is not something we can support or release without repeatable CI coverage of the affected environment.\n\nWe are therefore waiting on Progress/Chef to provide either a supported way to reproduce Chef 19 Habitat builds in CI or an upstream fix for the Habitat package and native-library boundary. Please raise this through Progress Support and link any support case or upstream issue here so we can track it.\n\nWe will keep this issue open under the chef-19, habitat, and waiting labels. We are closing #834 rather than shipping a runtime-specific workaround that we cannot continuously verify.

  4. damacus commented on Aug 11, 2026

    @damacus
    Member

    If you're still looking at v19, you might be better off going for Cinc in the mean time.

  5. mwrock commented on Aug 17, 2026

    @mwrock
    Contributor

    Hi, thanks for the detailed report. I dug into this and can confirm the root cause, and it's not  -z nodefaultlib. I couldn't find that flag referenced anywhere in Habitat's core/glibc , or  core/gcc , and testing confirms the actual mechanism is different.

    Root cause

    The  pg  gem's  extconf.rb  bakes the path passed via  --with-pg-lib  into the compiled  pg_ext.so  as a  DT_RUNPATH  dynamic tag.  DT_RUNPATH  is only used to resolve the extension's own direct dependency ( libpq.so.5 ) - it is explicitly not inherited by that library's own transitive dependencies ( libssl.so.3 ,  libldap.so.2 ,  libkrb5.so.3 , etc., per the ELF spec).

    Chef Infra Client, when packaged via Habitat, runs its bundled Ruby under Habitat's own private  core/glibc / ld-linux-x86-64.so.2  (a distinct  PT_INTERP  from the host's system loader). This is a vanilla, non-Debian-patched glibc build, so it lacks the Debian/Ubuntu multiarch default search directories ( /usr/lib/x86_64-linux-gnu ) compiled into its  system_dirs , and there's no  LD_LIBRARY_PATH  set to compensate. The result:  libpq.so.5  itself resolves fine (direct dependency, covered by  DT_RUNPATH ), but one hop down,  libssl.so.3  (and friends) fail to resolve, which is exactly the confusing part of the original error, since it doesn't complain about  libpq.so.5  at all.

    The fix

    Passing  --with-ldflags=-Wl,--disable-new-dtags  to the  pg  gem's native extension build forces the linker to emit the legacy  DT_RPATH  tag instead of  DT_RUNPATH . Critically,  DT_RPATH  is inherited by everything subsequently resolved down the dependency chain, so it also fixes  libpq.so.5 's own dependency resolution without needing to touch Habitat's  LD_LIBRARY_PATH  at all.

    Verified via  readelf -d  before/after:

    baseline (broken):

    0x000000000000001d (RUNPATH) Library runpath: [.../ruby3_4/.../lib:/usr/lib/x86_64-linux-gnu]

    fixed:

    0x000000000000000f (RPATH) Library rpath: [.../ruby3_4/.../lib:/usr/lib/x86_64-linux-gnu]

    Same paths, different tag — and  require 'pg'  goes from failing with the  libssl.so.3   LoadError  to succeeding.

    Validation

    I reproduced this both at the gem level (bare  hab pkg exec chef/chef-infra-client ruby -e "require 'pg'" ) and end-to-end via a real  chef-client -z  convergence of  postgresql_user / postgresql_database  resources against a local PostgreSQL server, using the Habitat-packaged  chef-infra-client :

    • Without the fix: convergence fails during  postgresql_user[...]  with  LoadError: pg's C extension failed to load: ... libpq.so.5: cannot open shared object file .
    • With the fix: convergence completes successfully, and the role/database are created as expected.

    I've opened a fix that updates  pg_gem_build_options  in  libraries/sql/_connection.rb  to add  --with-ldflags=-Wl,--disable-new-dtags  on both the RHEL/Amazon and Debian branches. While in there, I also corrected a separate (non-blocking) bug on the Debian branch, where  --with-pg-lib  was accidentally passed the include directory instead of the actual multiarch lib directory (this didn't break anything in practice because  pg 's  extconf.rb  falls back to  pg_config  regardless, but it was still wrong).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Upstream BugBug in upstream vendor applicationchef-19Issues specific to Chef Infra Client 19habitatIssues specific to Chef Habitat packaging or runtimewaitingWaiting on an external dependency or vendor response

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions