Skip to content

Bug: sdk/helper/ldaputil: errwrap {{err}} placeholder passed to fmt.Errorf, producing malformed error messages #32063

Description

@drewmullen

Describe the bug

First recorded: hashicorp/vault-plugin-secrets-openldap#183

Six call sites in sdk/helper/ldaputil/client.go build a format string containing the errwrap placeholder {{err}} and pass it to fmt.Errorf along with an error argument. fmt.Errorf does not interpret {{err}}, and the format string has no verb to consume the argument, so Go appends %!(EXTRA ...).

The result is a user-facing error containing both an uninterpreted {{err}} literal and a Go formatting-error marker:

error connecting to host "ldaps://dc1.example.com:636": {{err}}%!(EXTRA *ldap.Error=LDAP Result Code 200 "Network Error": dial tcp 10.0.0.1:636: i/o timeout)

Expected:

error connecting to host "ldaps://dc1.example.com:636": LDAP Result Code 200 "Network Error": dial tcp 10.0.0.1:636: i/o timeout

This looks like leftover from the errwrapfmt migration. Elsewhere in the codebase {{err}} is used correctly with errwrap.Wrapf, which does interpret it; these six use fmt.Errorf, which does not.

A secondary consequence: because %w is not used, the underlying error is not wrapped, so errors.Is / errors.As cannot reach it.

Affected lines

All in sdk/helper/ldaputil/client.go, present on main at c6c940dde7e050c9cc5f41cfc7329227a85115ad:

Line Message
40 error parsing url %q
107 error connecting to host %q
456 SID %#v convert failed reading Revision
460 SID %#v convert failed reading SubAuthorityCount
464 SID %#v convert failed reading IdentifierAuthority
470 SID %#v convert failed reading SubAuthority

For example, line 107:

retErr = multierror.Append(retErr, fmt.Errorf(fmt.Sprintf("error connecting to host %q: {{err}}", uut), err))

To Reproduce

  1. Configure any component that uses ldaputil against an unreachable host or port — the LDAP auth method, or the LDAP/AD secrets engine via vault-plugin-secrets-openldap.
  2. Trigger an operation that must reach the directory. For the secrets engine, issuing or revoking a dynamic credential is enough:
vault lease revoke -sync ldap/creds/<role>/<lease-id>
  1. Observe the returned error.

Expected behavior

The underlying LDAP error is reported without the {{err}} literal or the %!(EXTRA ...) marker, and is wrapped such that errors.Is / errors.As work.

Impact

  • User-facing error messages are malformed.
  • Log-based alerting that pattern-matches on these error strings will not match, because the literal text differs from what the message is meant to say. This is the practical problem: the connection failure is still legible to a human inside the EXTRA block, but not to a monitoring rule.
  • Callers cannot unwrap to inspect the underlying *ldap.Error.

Affects both the built-in LDAP auth method (builtin/credential/ldap) and the LDAP/AD secrets engines, which reach ldaputil through vault-plugin-secrets-openldap.

Prior mention

This was noticed and correctly attributed during unrelated work in vault-plugin-secrets-openldap#183, which contains the same output and the note:

(Note the {{err}}%!(EXTRA issue is coming from the ldaputil client).

It does not appear to have been filed separately, which is presumably why it is still present.

Suggested fix

// before
fmt.Errorf(fmt.Sprintf("error connecting to host %q: {{err}}", uut), err)

// after
fmt.Errorf("error connecting to host %q: %w", uut, err)

Applied to all six call sites. Using %w also restores errors.Is / errors.As support.

Environment

  • Vault version: present on main at c6c940dde7 (2026-07-31)
  • SDK versions checked: v0.23.0, v0.24.0, v0.25.1 — all six occurrences present in each
  • Age: line 107 last modified in cc570c11bb (2022-10-26)
  • Observed on: Vault 2.0.1+ent with vault-plugin-secrets-openldap, against Windows Server 2022 AD over LDAPS

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions