debugging
Diagnose and resolve Java/Spring Boot bugs, exceptions, and runtime issues using systematic debugging strategies. Use this skill whenever the user shares an error, stack trace, or unexpected behavior
SKILL.mdskills/debugging/SKILL.md
GitHubJava Debugging Skill
Systematically diagnose Java/Spring Boot issues using pattern recognition, stack trace analysis, and targeted investigation strategies.
Debugging Framework
Always follow this sequence:
- Identify: What type of error is it? (exception type, layer, timing)
- Locate: Where in the stack trace does the problem originate?
- Hypothesize: What are the 2-3 most likely root causes?
- Verify: What log output or code change would confirm/deny each hypothesis?
- Fix: Apply the minimal targeted fix.
Common Spring Boot Exceptions & Solutions
Application Startup Failures
NoSuchBeanDefinitionException
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type 'com.example.UserService' available
→ Causes & fixes:
- Missing
@Service/@Componentannotation → add it - Class not in component scan path → check
@SpringBootApplicationpackage - Interface injected but no implementation → verify impl class has
@Service - Multiple implementations without
@Primaryor@Qualifier→ add qualifier
BeanCreationException
Error creating bean with name 'dataSource': ...
→ Causes:
- Missing DB dependency in
pom.xml - Wrong DB URL / credentials in
application.yml - DB not reachable at startup
→ Check
application.yml, DB is running, driver on classpath
UnsatisfiedDependencyException
→ Circular dependency: A → B → A
// Fix with @Lazy on one injection point
public ClassA(@Lazy ClassB classB) { ... }
// Or restructure to remove the cycle
Runtime Exceptions
NullPointerException
java.lang.NullPointerException at UserService.java:42
→ Debug strategy:
- Look at line 42 — which object is null?
- Is it a Spring-injected bean? → check
@Service/@Autowired - Is it data from DB? → the entity field may not be loaded (lazy)
- Is it from a method return value? → check for null return
// Add defensive logging before NPE
log.debug("user={}, user.address={}", user, user != null ? user.getAddress() : "N/A");
LazyInitializationException
org.hibernate.LazyInitializationException: failed to lazily initialize a collection
→ Cause: accessing lazy collection outside a transaction → Fixes (pick one):
// Option 1: Use JOIN FETCH in the query
@Query("SELECT u FROM User u LEFT JOIN FETCH u.orders WHERE u.id = :id")
// Option 2: Use @Transactional on the calling method
// Option 3: Use @EntityGraph
@EntityGraph(attributePaths = "orders")
Optional<User> findById(Long id);
// ❌ DO NOT: open-in-view: true (anti-pattern)
OptimisticLockException / StaleObjectStateException
→ Cause: two threads updated the same entity simultaneously
→ Fix:
@Version
private Long version; // Add to entity for optimistic locking
// Handle in service
try {
return repository.save(entity);
} catch (OptimisticLockException e) {
throw new ConflictException("Resource was modified by another user, please retry");
}
DataIntegrityViolationException
→ Cause: unique constraint, FK constraint, or NOT NULL violation
→ Debug: read the nested ConstraintViolationException message for the constraint name
→ Fix: validate before save, or catch and throw a domain exception:
try {
return userRepository.save(user);
} catch (DataIntegrityViolationException e) {
if (e.getMessage().contains("users_email_key")) {
throw new ConflictException("Email already in use");
}
throw e;
}
TransactionRequiredException
→ Cause: modifying entity outside transaction
→ Fix: add @Transactional to the service method
HTTP / Controller Issues
400 Bad Request (unexpected)
→ Check order:
@Validon@RequestBodyparameter?- Bean Validation annotations on DTO fields?
- JSON field names match DTO field names?
- Correct
Content-Type: application/jsonheader?
404 Not Found (for existing endpoint)
→ Check:
@RequestMappingbase path correct?- HTTP method matches? (
@GetMappingvs@PostMapping) - Path variable name matches:
@PathVariable Long idvs/{id} - Context path in
application.yml?
500 Internal Server Error
→ Always check the server logs — the stack trace is in the logs, not in the response body (by design)
→ Enable detailed error output for dev:
server:
error:
include-message: always
include-binding-errors: always
HttpMessageNotReadableException
→ Jackson can't deserialize the JSON body
→ Check: LocalDate/LocalDateTime needs @JsonFormat or Jackson JavaTime module:
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate birthDate;
Debugging Tools & Techniques
Enable SQL Logging
spring:
jpa:
show-sql: true
properties.hibernate.format_sql: true
logging:
level:
org.hibernate.SQL: DEBUG
org.hibernate.type.descriptor.sql: TRACE # Show bind parameters
Enable Spring Debug Logging
logging:
level:
org.springframework.web: DEBUG # HTTP requests/responses
org.springframework.security: DEBUG # Security filter chain
org.springframework.transaction: DEBUG # Transaction boundaries
Actuator for Runtime Diagnosis
// Add to pom.xml: spring-boot-starter-actuator
// Check bean context
GET /actuator/beans
// Check env and config
GET /actuator/env
// Check health
GET /actuator/health
Minimal Reproducer Technique
When a bug is hard to isolate:
- Create a standalone
@SpringBootTesttest that reproduces the issue - Remove dependencies one by one until the bug disappears
- The last removed dependency is the cause
Stack Trace Reading Guide
Exception in thread "main" java.lang.NullPointerException ← Exception type
at com.example.service.UserService.findUser(UserService.java:42) ← YOUR code (root cause)
at com.example.controller.UserController.getUser(UserController.java:28)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ← Framework code (ignore)
...
Rule: Find the first line in YOUR package — that's where to start investigating. Ignore framework lines (Spring, Hibernate, JDK) unless your code has no visible lines.