{"record":{"id":"ce8c81305593162f","repo":"shadow1ng/fscan","slug":"auth-function-returned-nil-result","errorCode":null,"errorMessage":"auth function returned nil result","messagePattern":"auth function returned nil result","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"plugins/services/credential_tester.go","lineNumber":359,"sourceCode":"\tauthFn AuthFunc,\n\tserviceName string,\n\ttestConfig ConcurrentTestConfig,\n) (*ScanResult, ErrorType) {\n\tfor attempt := 0; attempt < testConfig.MaxRetries; attempt++ {\n\t\t// 检查是否应该停止\n\t\tselect {\n\t\tcase <-ctx.Done():\n\t\t\treturn nil, ErrorTypeUnknown\n\t\tdefault:\n\t\t}\n\n\t\t// 测试凭据\n\t\tresult := TestSingleCredential(ctx, cred, authFn)\n\t\tif result == nil {\n\t\t\tresult = &AuthResult{\n\t\t\t\tSuccess:   false,\n\t\t\t\tErrorType: ErrorTypeUnknown,\n\t\t\t\tError:     fmt.Errorf(\"auth function returned nil result\"),\n\t\t\t}\n\t\t}\n\n\t\tif result.Success {\n\t\t\tif result.Conn != nil {\n\t\t\t\t_ = result.Conn.Close()\n\t\t\t}\n\t\t\treturn &ScanResult{\n\t\t\t\tType:     plugins.ResultTypeCredential,\n\t\t\t\tSuccess:  true,\n\t\t\t\tService:  serviceName,\n\t\t\t\tUsername: cred.Username,\n\t\t\t\tPassword: cred.Password,\n\t\t\t}, ErrorTypeUnknown\n\t\t}\n\n\t\t// 根据错误类型决定是否重试\n\t\tswitch result.ErrorType {","sourceCodeStart":341,"sourceCodeEnd":377,"githubUrl":"https://github.com/shadow1ng/fscan/blob/95cc12e753bf43de7004e5aef42a9ffba3934303/plugins/services/credential_tester.go#L341-L377","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nfunc authFn(ctx context.Context, cred Credential) *AuthResult {\n    if err != nil {\n        return nil\n    }\n// after\nfunc authFn(ctx context.Context, cred Credential) *AuthResult {\n    if err != nil {\n        return &AuthResult{Success: false, ErrorType: ErrorTypeUnknown, Error: err}\n    }","handlingStrategy":"type-guard","validationCode":"if authFn == nil {\n    return errors.New(\"authFn must not be nil\")\n}","typeGuard":"func nonNilResult(r *AuthResult, err error) *AuthResult {\n    if r != nil {\n        return r\n    }\n    return &AuthResult{Success: false, ErrorType: ErrorTypeUnknown, Error: fmt.Errorf(\"nil result: %v\", err)}\n}","tryCatchPattern":"result := TestSingleCredential(ctx, cred, authFn)\nif result == nil {\n    log.Printf(\"BUG: TestSingleCredential returned nil for %+v\", cred)\n    result = &AuthResult{Success: false, ErrorType: ErrorTypeUnknown, Error: errors.New(\"nil result\")}\n}","preventionTips":["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"],"tags":["go","nil-pointer","contract","concurrency"],"backgroundTag":"internal-invariant-violation","analyzedSha":"95cc12e753bf43de7004e5aef42a9ffba3934303","analyzedAt":"2026-09-06T17:07:30.094Z","contentChangedAt":"2026-09-06T17:07:30.094Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}