{"record":{"id":"8f3d96d8f208d3e5","repo":"basecamp/kamal","slug":"failed-to-sync-bitwarden","errorCode":null,"errorMessage":"Failed to sync Bitwarden","messagePattern":"Failed to sync Bitwarden","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"lib/kamal/secrets/adapters/bitwarden.rb","lineNumber":19,"sourceCode":"class Kamal::Secrets::Adapters::Bitwarden < Kamal::Secrets::Adapters::Base\n  private\n    def login(account)\n      status = run_command(\"status\")\n\n      if status[\"status\"] == \"unauthenticated\"\n        run_command(\"login #{account.shellescape}\", raw: true)\n        status = run_command(\"status\")\n      end\n\n      if status[\"status\"] == \"locked\"\n        session = run_command(\"unlock --raw\", raw: true).presence\n        status = run_command(\"status\", session: session)\n      end\n\n      raise RuntimeError, \"Failed to login to and unlock Bitwarden\" unless status[\"status\"] == \"unlocked\"\n\n      run_command(\"sync\", session: session, raw: true)\n      raise RuntimeError, \"Failed to sync Bitwarden\" unless $?.success?\n\n      session\n    end\n\n    def fetch_secrets(secrets, from:, account:, session:)\n      {}.tap do |results|\n        items_fields(prefixed_secrets(secrets, from: from)).each do |item, fields|\n          item_json = run_command(\"get item #{item.shellescape}\", session: session, raw: true)\n          raise RuntimeError, \"Could not read #{item} from Bitwarden\" unless $?.success?\n          item_json = JSON.parse(item_json)\n          if fields.any?\n            results.merge! fetch_secrets_from_fields(fields, item, item_json)\n          elsif item_json.dig(\"login\", \"password\")\n            results[item] = item_json.dig(\"login\", \"password\")\n          elsif item_json[\"fields\"]&.any?\n            fields = item_json[\"fields\"].pluck(\"name\")\n            results.merge! fetch_secrets_from_fields(fields, item, item_json)\n          else","sourceCodeStart":1,"sourceCodeEnd":37,"githubUrl":"https://github.com/basecamp/kamal/blob/eee0083b38661c3707c6b6052cc89e85038a096c/lib/kamal/secrets/adapters/bitwarden.rb#L1-L37","documentation":"After a successful login/unlock, the Bitwarden adapter runs `bw sync` to pull the latest vault; if that command exits non-zero ($?.success? false), Kamal raises RuntimeError \"Failed to sync Bitwarden\". Sync is required so subsequent `bw get item` calls see current vault contents.","triggerScenarios":"Transient network failure reaching Bitwarden's API; an invalidated session (BW_SESSION rejected server-side mid-run); Bitwarden service outage or self-hosted server down; clock skew breaking TLS.","commonSituations":"Flaky connectivity on CI runners; long-running agents whose session expires between unlock and sync; self-hosted Bitwarden (Vaultwarden) instances restarting during deploy.","solutions":["Retry the kamal secrets fetch — sync failures are often transient","Run bw sync manually to see the underlying error; if it reports an invalid session, bw unlock again and re-export BW_SESSION","Check connectivity/health of api.bitwarden.com (or your self-hosted server) and system clock accuracy","Re-login from scratch (bw logout && bw login) if the account state is corrupted"],"exampleFix":"# before\nkamal secrets fetch -a bitwarden --account me@example.com RAILS_MASTER_KEY\n# => RuntimeError: Failed to sync Bitwarden\n\n# fix (terminal)\nbw sync                 # reproduce / see error\nbw unlock               # refresh session if invalid\nexport BW_SESSION=...\nkamal secrets fetch -a bitwarden --account me@example.com RAILS_MASTER_KEY","handlingStrategy":"retry","validationCode":"abort \"bitwarden unreachable / not synced\" unless system(\"bw sync > /dev/null 2>&1\")","typeGuard":null,"tryCatchPattern":"attempts = 0\nbegin\n  adapter.fetch(names, account: account)\nrescue RuntimeError => e\n  attempts += 1\n  if e.message.include?(\"Failed to sync Bitwarden\") && attempts < 3\n    sleep 2 ** attempts\n    retry\n  end\n  raise\nend","preventionTips":["Treat sync failures as transient: retry with backoff before failing the deploy","Run `bw sync` as a pre-flight in CI to distinguish vault-outage from item problems"],"tags":["kamal","secrets","bitwarden","sync","network"],"backgroundTag":"vault-sync-failed","analyzedSha":"eee0083b38661c3707c6b6052cc89e85038a096c","analyzedAt":"2026-08-21T15:17:22.045Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}