henrygd/beszel · error
fingerprint mismatch
Error message
fingerprint mismatch
What it means
handleSingleRecord finds exactly one fingerprint record for the token. If the record has a fingerprint but it doesn't equal the fingerprint the connecting agent presents, the hub aborts with 'fingerprint mismatch' — the token belongs to a different machine, which could indicate token reuse or a cloned/rebuilt host.
Source
Thrown at internal/hub/agent_connect.go:215
return acr.createNewSystemForUniversalToken(agentFingerprint)
}
// handleSingleRecord handles the case with a single fingerprint record. It validates
// the agent's fingerprint against the stored one, or sets it on first connect.
func (acr *agentConnectRequest) handleSingleRecord(fpRecord ws.FingerprintRecord, agentFingerprint common.FingerprintResponse) (ws.FingerprintRecord, error) {
// If no current fingerprint, update with new fingerprint (first time connecting)
if fpRecord.Fingerprint == "" {
if err := acr.hub.SetFingerprint(&fpRecord, agentFingerprint.Fingerprint); err != nil {
return fpRecord, err
}
// Update the record with the fingerprint that was set
fpRecord.Fingerprint = agentFingerprint.Fingerprint
return fpRecord, nil
}
// Abort if fingerprint exists but doesn't match (different machine)
if fpRecord.Fingerprint != agentFingerprint.Fingerprint {
return fpRecord, errors.New("fingerprint mismatch")
}
return fpRecord, nil
}
// handleMultipleRecordsOrUniversalToken finds a matching fingerprint from multiple records.
// If no match is found and the token is a universal token, a new system is created.
func (acr *agentConnectRequest) handleMultipleRecordsOrUniversalToken(fpRecords []ws.FingerprintRecord, agentFingerprint common.FingerprintResponse) (ws.FingerprintRecord, error) {
// Return existing record with matching fingerprint if found
for i := range fpRecords {
if fpRecords[i].Fingerprint == agentFingerprint.Fingerprint {
return fpRecords[i], nil
}
}
// No matching fingerprint record found, but it's
// an active universal token so create a new system
if acr.isUniversalToken {View on GitHub (pinned to b38fb7dafa)
Solutions
- Remove the system in the hub and re-add it so the new fingerprint is accepted with a fresh token
- If the fingerprint changed legitimately (container rebuilt), update/reset the stored fingerprint record
- Ensure the KEY is unique per system — never share one token across agents
- Check that a proxy isn't routing two different agents through one system entry
Example fix
// before: same KEY on two machines KEY=<shared-key> on host-a and host-b // after: unique key per system host-a: KEY=<token-a> host-b: KEY=<token-b>
Defensive patterns
Strategy: validation
Validate before calling
// ensure each host has its own key before deploy
if keyInUseOnAnotherHost(agentKey) {
log.Fatal("KEY already bound to another system; generate a new one")
} Try / catch
rec, err := acr.handleSingleRecord(fp)
if err != nil && err.Error() == "fingerprint mismatch" {
// recreate container/hardware change: re-add the system in hub
return reRegisterSystem()
} Prevention
- Never reuse one KEY across multiple agents
- After rebuilding a container/VM or reinstalling, re-add the system in the hub
- Store keys per-host in your config management, not shared templates
- Watch for cloned disk images carrying stale keys
When it happens
Trigger: Agent connects; its token resolves to a single stored record whose Fingerprint differs from agentFingerprint.Fingerprint (e.g. agent reinstalled, container recreated, or key copied to a second machine).
Common situations: Copying the same KEY to multiple agents; recreating a Docker container so its generated fingerprint changed; disk reinstall or hardware change; agent moved to a different host without re-adding the system in the hub.
Related errors
- hub not verified
- no matching fingerprints
- must set TOKEN or TOKEN_FILE
- invalid signature - check KEY value
- fingerprint file is empty
AI-assisted analysis of henrygd/beszel@b38fb7dafa (2026-08-31).
Data as JSON: /api/errors/a7139072178a340b.
Report an issue: GitHub.