{"record":{"id":"56ae92246aca3a04","repo":"gastownhall/beads","slug":"failed-to-get-peer-credentials-w","errorCode":null,"errorMessage":"failed to get peer credentials: %w","messagePattern":"failed to get peer credentials: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/dolt/credentials.go","lineNumber":610,"sourceCode":"\n// withEnvCredentials executes fn with credentials set as process-wide env vars,\n// protected by federationEnvMutex. This is required for SQL-path operations\n// (CALL DOLT_PUSH/PULL) where the in-process Dolt server reads credentials\n// from the process environment. CLI operations should NOT use this — use\n// remoteCredentials.applyToCmd instead for race-free subprocess isolation.\nfunc withEnvCredentials(creds *remoteCredentials, fn func() error) error {\n\treturn withRemoteOperationEnv(creds, false, fn)\n}\n\n// withPeerCredentials looks up credentials for a federation peer and passes\n// them to fn. The callback receives the credentials and is responsible for\n// applying them appropriately: CLI operations use creds.applyToCmd for\n// subprocess isolation; SQL operations use withEnvCredentials for mutex-protected\n// process env access.\nfunc (s *DoltStore) withPeerCredentials(ctx context.Context, peerName string, fn func(creds *remoteCredentials) error) error {\n\tpeer, err := s.GetFederationPeer(ctx, peerName)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get peer credentials: %w\", err)\n\t}\n\n\tvar creds *remoteCredentials\n\tif peer != nil && (peer.Username != \"\" || peer.Password != \"\") {\n\t\tcreds = &remoteCredentials{username: peer.Username, password: peer.Password}\n\t}\n\n\terr = fn(creds)\n\n\t// Update last sync time on success\n\tif err == nil && peer != nil {\n\t\t_ = s.updatePeerLastSync(ctx, peerName) // Best effort: peer sync timestamp is advisory\n\t}\n\n\treturn err\n}\n\n// FederationPeer is an alias for storage.FederationPeer for convenience.","sourceCodeStart":592,"sourceCodeEnd":628,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/dolt/credentials.go#L592-L628","documentation":"withPeerCredentials fetches a federation peer's stored credentials before running a push/pull/fetch callback. This error wraps any failure from GetFederationPeer — most commonly the peer not existing (storage.ErrNotFound 'federation peer <name>'), but also SQL failures and password decryption failures. The library throws it so sync operations fail early with a credential-lookup message instead of attempting an unauthenticated remote operation.","triggerScenarios":"Calling pushRefToPeer/pullFromPeer/Fetch with a peer name that has no row in federation_peers (never added via AddFederationPeer or already removed); the underlying SELECT fails (connection down); or the stored password can't be decrypted.","commonSituations":"Typo in the peer/remote name when syncing; removing a peer but still pushing to it from a script; database connectivity loss; key-file mismatch causing decrypt errors surfaced here.","solutions":["Check the peer exists: GetFederationPeer with the exact name; add it via AddFederationPeer if missing.","Fix the name typo — names are case-sensitive and validated (alphanumeric/hyphen/underscore).","If the inner error is a decrypt/key error, restore .beads/.beads-credential-key or re-add the peer's password.","If it's a connectivity error, reconnect to the dolt-sql-server and retry."],"exampleFix":"// before\nerr := store.Push(ctx, ...) // failed to get peer credentials: federation peer alice not found\n// after: register the peer first\nerr = store.AddFederationPeer(ctx, &storage.FederationPeer{Name: \"alice\", RemoteURL: \"https://doltremoteapi.dolthub.com/org/repo\", Username: \"u\", Password: \"p\"})","handlingStrategy":"type-guard","validationCode":"// check peer exists before sync operations\nif _, err := store.GetFederationPeer(ctx, peerName); err != nil {\n    return fmt.Errorf(\"peer %q not configured; add it via AddFederationPeer\", peerName)\n}","typeGuard":"func isPeerNotFound(err error) bool {\n    return errors.Is(err, storage.ErrNotFound) && strings.Contains(err.Error(), \"federation peer\")\n}","tryCatchPattern":"err := store.Push(ctx, ...)\nif isPeerNotFound(err) {\n    // register the peer then retry\n    if addErr := store.AddFederationPeer(ctx, &storage.FederationPeer{Name: peerName, RemoteURL: url, Username: u, Password: p}); addErr != nil { return addErr }\n    err = store.Push(ctx, ...)\n}","preventionTips":["Validate peer names against ListFederationPeers before syncing","Remove peers and their consuming scripts together","Store peer names in config rather than hardcoding strings","Handle storage.ErrNotFound distinctly from transient SQL errors"],"tags":["credentials","federation","not-found","sync"],"backgroundTag":"peer-credentials-not-found","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}