{"record":{"id":"3b6099fd6ca37f51","repo":"pinpoint-apm/pinpoint","slug":"securitycontext-not-found-th","errorCode":null,"errorMessage":"SecurityContext not found th:","messagePattern":"SecurityContext not found th:","errorType":"exception","errorClass":"AuthenticationCredentialsNotFoundException","httpStatus":null,"severity":"error","filePath":"user/src/main/java/com/navercorp/pinpoint/user/util/SecurityContextUtils.java","lineNumber":108,"sourceCode":"    }\n\n    public static <T extends Authentication> T getAuthentication(Class<T> clazz) {\n        final SecurityContext context = getSecurityContext();\n        final Authentication authentication = context.getAuthentication();\n        if (clazz.isInstance(authentication)) {\n            return cast(authentication);\n        }\n        return null;\n    }\n\n    private static String getThreadName() {\n        return Thread.currentThread().getName();\n    }\n\n    private static SecurityContext getSecurityContext() {\n        final SecurityContext context = STRATEGY.getContext();\n        if (context == null) {\n            throw new AuthenticationCredentialsNotFoundException(\"SecurityContext not found th:\" + getThreadName());\n        }\n        return context;\n    }\n}\n","sourceCodeStart":90,"sourceCodeEnd":113,"githubUrl":"https://github.com/pinpoint-apm/pinpoint/blob/744c3d3075e595656abb1ae331ad2c0e4c9eb996/user/src/main/java/com/navercorp/pinpoint/user/util/SecurityContextUtils.java#L90-L113","documentation":"SecurityContextUtils.getSecurityContext obtains the SecurityContext via the configured STRATEGY (SecurityContextHolder strategy) and throws AuthenticationCredentialsNotFoundException when it is null, including the thread name to aid debugging. Methods like context() rely on this, so any user-info lookup without an authenticated request fails here.","triggerScenarios":"Calling SecurityContextUtils.context()/helpers on a thread where no SecurityContext was ever set — unauthenticated requests, async worker threads, or code paths that skip the security filter chain.","commonSituations":"Background jobs or scheduled tasks accessing user info; requests to endpoints excluded from Spring Security; tests without a mock security context; thread-pool reuse after context clearing.","solutions":["Ensure the code runs within an authenticated request or set a SecurityContext for the thread (SecurityContextHolder.setContext or DelegatingSecurityContextRunnable).","Catch AuthenticationCredentialsNotFoundException and fall back to anonymous handling.","Wrap async work with DelegatingSecurityContextExecutor to propagate the context."],"exampleFix":"// before\nString userId = SecurityContextUtils.context().getAuthentication().getName(); // in async task\n// after\nRunnable wrapped = new DelegatingSecurityContextRunnable(() -> {\n    String userId = SecurityContextUtils.context().getAuthentication().getName();\n}, securityContext);","handlingStrategy":"try-catch","validationCode":"SecurityContext ctx = SecurityContextHolder.getContext();\nboolean hasAuth = ctx != null && ctx.getAuthentication() != null && ctx.getAuthentication().isAuthenticated();","typeGuard":"boolean hasSecurityContext(SecurityContext c) { return c != null && c.getAuthentication() != null; }","tryCatchPattern":"try { SecurityContext ctx = SecurityContextUtils.context(); ... } catch (AuthenticationCredentialsNotFoundException e) { /* anonymous fallback or defer */ }","preventionTips":["Propagate SecurityContext to async threads (DelegatingSecurityContextExecutor)","Guard calls to user-info utilities with authentication checks","Don't clear the context on pooled threads before dependent code runs"],"tags":["spring-security","security-context","authentication"],"backgroundTag":"authentication-required","analyzedSha":"744c3d3075e595656abb1ae331ad2c0e4c9eb996","analyzedAt":"2026-09-07T18:48:45.289Z","contentChangedAt":"2026-09-07T18:48:45.289Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}