shadow1ng/fscan · warning
auth function returned nil result
Error message
auth function returned nil result
What it means
Inside the retry loop, workerTestCredentials calls TestSingleCredential and guards against it returning nil. If it does, the worker synthesizes a failed AuthResult with this message so downstream code never dereferences a nil pointer. This signals a contract violation: TestSingleCredential (or the authFn it wraps) must always return a non-nil AuthResult, including on error.
Source
Thrown at plugins/services/credential_tester.go:359
authFn AuthFunc,
serviceName string,
testConfig ConcurrentTestConfig,
) (*ScanResult, ErrorType) {
for attempt := 0; attempt < testConfig.MaxRetries; attempt++ {
// 检查是否应该停止
select {
case <-ctx.Done():
return nil, ErrorTypeUnknown
default:
}
// 测试凭据
result := TestSingleCredential(ctx, cred, authFn)
if result == nil {
result = &AuthResult{
Success: false,
ErrorType: ErrorTypeUnknown,
Error: fmt.Errorf("auth function returned nil result"),
}
}
if result.Success {
if result.Conn != nil {
_ = result.Conn.Close()
}
return &ScanResult{
Type: plugins.ResultTypeCredential,
Success: true,
Service: serviceName,
Username: cred.Username,
Password: cred.Password,
}, ErrorTypeUnknown
}
// 根据错误类型决定是否重试
switch result.ErrorType {View on GitHub (pinned to 95cc12e753)
Solutions
- Fix the authFn so every code path returns a non-nil *AuthResult (return an AuthResult with Success:false and Error set instead of nil).
- Audit TestSingleCredential for early-return branches that omit a return value.
- Log when this guard fires to identify which credential/attempt produced the nil and add a regression test for that path.
- If you own neither function, keep the guard but count these occurrences as internal bugs rather than auth failures.
Example fix
// before
func authFn(ctx context.Context, cred Credential) *AuthResult {
if err != nil {
return nil
}
// after
func authFn(ctx context.Context, cred Credential) *AuthResult {
if err != nil {
return &AuthResult{Success: false, ErrorType: ErrorTypeUnknown, Error: err}
} Defensive patterns
Strategy: type-guard
Validate before calling
if authFn == nil {
return errors.New("authFn must not be nil")
} Type guard
func nonNilResult(r *AuthResult, err error) *AuthResult {
if r != nil {
return r
}
return &AuthResult{Success: false, ErrorType: ErrorTypeUnknown, Error: fmt.Errorf("nil result: %v", err)}
} Try / catch
result := TestSingleCredential(ctx, cred, authFn)
if result == nil {
log.Printf("BUG: TestSingleCredential returned nil for %+v", cred)
result = &AuthResult{Success: false, ErrorType: ErrorTypeUnknown, Error: errors.New("nil result")}
} Prevention
- Contract-test authFn: every path returns non-nil *AuthResult
- Replace `return nil` on error with a failed AuthResult carrying the error
- Add CI assertions that TestSingleCredential never returns nil
- Count guard hits as internal bugs in monitoring
When it happens
Trigger: TestSingleCredential returning nil because the wrapped authFn returned nil, or a code path in TestSingleCredential that forgot its return value on an early error branch.
Common situations: Custom authFn implementations that `return nil` on error instead of returning an AuthResult with an Error field; library upgrades where the authFn signature/contract changed; race conditions where a result channel path skips assignment.
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 panic: %v
- 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/ce8c81305593162f.
Report an issue: GitHub.