shadow1ng/fscan · error
auth function panic: %v
Error message
auth function panic: %v
What it means
This error is produced by a panic-recovery wrapper around the per-credential auth function. TestSingleCredential runs authFn inside a goroutine with a deferred recover(); if the user-supplied auth function panics (nil map write, nil pointer dereference, index out of range), the panic is converted into a failed AuthResult with ErrorTypeUnknown carrying this message. It indicates a bug inside the auth callback, not a network or credential problem.
Source
Thrown at plugins/services/credential_tester.go:105
}
}
if err := ctx.Err(); err != nil {
return &AuthResult{
Success: false,
ErrorType: ErrorTypeNetwork,
Error: err,
}
}
resultChan := make(chan *AuthResult, 1)
go func() {
defer func() {
if r := recover(); r != nil {
resultChan <- &AuthResult{
Success: false,
ErrorType: ErrorTypeUnknown,
Error: fmt.Errorf("auth function panic: %v", r),
}
}
}()
result := authFn(ctx, cred)
resultChan <- result
}()
select {
case result := <-resultChan:
return result
case <-ctx.Done():
// context 被取消后只做有界等待,避免 authFn 卡死时清理 goroutine 也永久泄漏。
go func() {
timer := time.NewTimer(authCleanupWait())
defer timer.Stop()
select {
case result := <-resultChan:View on GitHub (pinned to 95cc12e753)
Solutions
- Inspect the %v payload in the message to find the panic value (usually 'runtime error: nil pointer dereference' or 'index out of range') and fix the offending line in the authFn callback.
- Add nil/empty checks for cred.Username, cred.Password and any parsed response fields inside the auth function before using them.
- Wrap risky parsing logic inside the authFn in its own recover() if partial results are acceptable.
- Test the authFn against empty/zero-value Credential structs in unit tests to surface panics early.
Example fix
// before
result := conn.Auth(cred.Username, cred.Password, parseDomains(resp))
// after
if cred.Username == "" || cred.Password == "" {
return &AuthResult{Success: false, ErrorType: ErrorTypeAuth, Error: errors.New("empty credential")}
}
result := conn.Auth(cred.Username, cred.Password, parseDomains(resp)) Defensive patterns
Strategy: try-catch
Validate before calling
if cred == (Credential{}) || authFn == nil {
return errors.New("invalid credential or auth function")
} Type guard
func safeAuthFn(authFn AuthFn) AuthFn {
return func(ctx context.Context, cred Credential) *AuthResult {
defer func() { _ = recover() }()
return authFn(ctx, cred)
}
} Try / catch
res := <-resultChan
if res.Error != nil && strings.HasPrefix(res.Error.Error(), "auth function panic:") {
// recoverable: log panic payload, mark credential attempt as errored, continue
log.Printf("authFn panicked: %v", res.Error)
return
} Prevention
- Never dereference Credential fields without nil/empty checks inside authFn
- Unit-test authFn with zero-value credentials
- Keep parsing of service responses inside functions with their own recover
- Run go vet / race detector on custom auth functions
When it happens
Trigger: Calling Scan/TestCredentialsConcurrently with an authFn that panics on the given ctx/credential — e.g. dereferencing a nil field in the Credential, indexing a slice without bounds checks, or writing to a nil map when parsing the service response.
Common situations: Custom auth functions written without nil checks; credentials with empty Username/Password fields the callback assumes are populated; a service banner response that the callback parses unconditionally; refactoring the callback so a field becomes nil at runtime.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- auth function returned nil result
- output manager is closed
- writer is closed
- failed to write realtime backup: %w
- failed to sync realtime backup: %w
AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06).
Data as JSON: /api/errors/8953030c04861079.
Report an issue: GitHub.