Spring Could Not Resolve Placeholder — Missing Property
Fix Spring "Could not resolve placeholder" by adding the missing property, checking profile-specific files, and verifying the property source order.
Symptoms
- ApplicationContext fails with "Could not resolve placeholder 'x' in value \"${x}\""
- Works with the dev profile but fails in prod
- The property exists in a file that is not being loaded
Possible causes
- The property is missing from the active profile or environment
- A profile-specific file such as application-prod.properties is not on the classpath
- A default value was not provided for an optional @Value
Diagnosis steps
Read the exact placeholder name
java -jar app.jar 2>&1 | grep -A 2 "Could not resolve placeholder"Interpretation
The message names the unresolved key, which tells you which property to add.
Inspect the active profiles and property sources
java -jar app.jar --debug 2>&1 | grep -A 20 "PropertySourcesPlaceholder"Interpretation
The debug log lists loaded property sources and profiles, revealing where the value should come from.
Root cause
Spring resolves ${...} placeholders against the active environment at bean creation. If no property source, profile file, or environment variable supplies the key and no default is given, resolution fails and the context aborts.
Fix
Add the property to the correct profile file, pass it as an environment variable, or supply a default with @Value("${x:default}"); verify which profiles are active in each environment.
Risk note
Defaults can mask missing production config; prefer failing fast for required values and defaulting only genuinely optional ones.
Verify the fix
Start the application with the target profile and confirm the context loads; log the resolved value (redacted) to prove the property source is correct.
Symptoms
This debugging guide addresses “Spring Could Not Resolve Placeholder — Missing Property”. Start from the symptoms, follow the ordered diagnostics, and confirm each hypothesis before moving on; the fix and verification steps then close the loop.
Observed symptoms include:
- ApplicationContext fails with “Could not resolve placeholder ‘x’ in value "${x}"”
- Works with the dev profile but fails in prod
- The property exists in a file that is not being loaded
Reproduce and Diagnose
Reproduce the failure in isolation before changing any code. Work through the checks below in order; each one narrows the search space.
Step 1: Read the exact placeholder name
java -jar app.jar 2>&1 | grep -A 2 "Could not resolve placeholder"
The message names the unresolved key, which tells you which property to add.
Step 2: Inspect the active profiles and property sources
java -jar app.jar --debug 2>&1 | grep -A 20 "PropertySourcesPlaceholder"
The debug log lists loaded property sources and profiles, revealing where the value should come from.
Likely contributors, in order of frequency:
- The property is missing from the active profile or environment
- A profile-specific file such as application-prod.properties is not on the classpath
- A default value was not provided for an optional @Value
Root Cause
Spring resolves ${…} placeholders against the active environment at bean creation. If no property source, profile file, or environment variable supplies the key and no default is given, resolution fails and the context aborts.
The Fix
Add the property to the correct profile file, pass it as an environment variable, or supply a default with @Value(“${x:default}”); verify which profiles are active in each environment.
Watch out: Defaults can mask missing production config; prefer failing fast for required values and defaulting only genuinely optional ones.
@Service
public class MailService {
// required -> fail fast if absent
@Value("${mail.host}")
private String host;
// optional -> explicit default
@Value("${mail.port:587}")
private int port;
}
# application-prod.properties
mail.host=smtp.example.com
Verify and Prevent
Start the application with the target profile and confirm the context loads; log the resolved value (redacted) to prove the property source is correct.
Once verified, add a regression test that reproduces the original symptom so the failure cannot silently return.
This class of failure is usually environmental rather than pure logic, so capture the exact command, the environment variables, and the working directory in your bug report. Reproduce it in the smallest possible script, then widen the scope only once the minimal case is understood. A short written checklist for this failure mode saves hours the next time it appears.