Swap move selector applies entity value range filtering to entity classes without entity-level ranges
I maintainer di solito rispondono entro 1 giorno
@zepfred ci sta già lavorando.
Dal 15/10/2026.
Valutazione
Questa issue non è ancora stata valutata.
Descrizione
Summary
Once any basic variable in the model has an entity-level value range, the default swap move selector
turns on entity value range filtering for every entity class with basic variables, including classes
whose variables only have solution-level ranges. Local search then crashes when it starts.
List variables are not affected: only basic variables are checked.
Error
java.lang.IllegalStateException: Impossible state: no basic variable found for the entity class org.acme.projectjobschedule.domain.ProjectLead.
at ai.timefold.solver.core.impl.heuristic.selector.entity.decorator.FilteringEntityByEntitySelector.phaseStarted(FilteringEntityByEntitySelector.java:104)
...
at ai.timefold.solver.core.impl.neighborhood.MoveSelectorBasedMoveRepository.phaseStarted(MoveSelectorBasedMoveRepository.java:43)
at ai.timefold.solver.core.impl.localsearch.decider.LocalSearchDecider.phaseStarted(LocalSearchDecider.java:78)
at ai.timefold.solver.core.impl.localsearch.DefaultLocalSearchPhase.phaseStarted(DefaultLocalSearchPhase.java:136)
at ai.timefold.solver.core.impl.localsearch.DefaultLocalSearchPhase.solve(DefaultLocalSearchPhase.java:76)
Root cause
SwapMoveSelectorFactory.java (lines 44-47) decides whether to enable entity value range filtering by
looking at all basic variables in the solution, not just those of the entity class being swapped:
var entityDescriptor = deduceEntityDescriptor(configPolicy, entitySelectorConfig.getEntityClass());
var enableEntityValueRangeFilter = entityDescriptor.getSolutionDescriptor().getBasicVariableDescriptorList()
.stream()
.anyMatch(v -> !v.canExtractValueRangeFromSolution());
The default swap move selector is unfolded into one child selector per entity class with basic variables.
For an entity class whose variables all have solution-level ranges, the check above still returns true
because of another entity class, so a recorder ID is set and the right entity selector is wrapped in
FilteringEntityByEntitySelector. That selector then finds no entity-level range on this class and throws.
Suggested fix
Scope the check to the entity class being swapped (ideally to the variables the selector actually uses,
honoring variableNameIncludeList):
var enableEntityValueRangeFilter = deduceBasicVariableDescriptorList(entityDescriptor, config.getVariableNameIncludeList())
.stream()
.anyMatch(v -> !v.canExtractValueRangeFromSolution());
Reproducer
Quickstart use-cases/project-job-scheduling, branch bug/reproduce-multi-entity-value-range:
Allocation(existing) has basic variables with entity-level ranges (executionMode,delay).ProjectLead(new) has a basic variableresourcewhose range comes from the solution
(@ValueRangeProvideronProjectJobSchedule.resources).MultiEntityValueRangeReproducerTestsolves for 5 seconds without a best score limit, so the
local search phase runs and crashes.
Note: the existing SolverManagerTest does not catch this because the test profile's best score limit
ends the solve before local search starts.
Workaround
Give every other entity class with basic variables an entity-level range too, even if it just lists every
value:
@ValueRangeProvider
public List<Resource> getResourceRange() {
return resourceRange; // all resources
}
With this in place, the reproducer passes and local search runs normally.
Environment
- Reproduced with the local
timefold-solver999-SNAPSHOT(built 2026-10-12); the same code is on
solvermain. Reported against 2.7.
- Lingua principale
- Java
- Stelle
- 1.8k
- Fork
- 238
- Merge medio
- 3g 2h
- PR unite (30g)
- 59
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Nessun modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di TimefoldAI/timefold-solver
-
component/docs
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
TimefoldAI/timefold-solver#2671 ·
I maintainer di solito rispondono entro 1 giorno
-
SDK: Waypoints class has not OpenAPI Spec annotations.Forse già presa @TomCools l’ha presa oggi. Apertacomponent/service
TimefoldAI/timefold-solver#2759 · 1 assegnatario ·
I maintainer di solito rispondono entro 1 giorno
-
process/needs triage
Difficoltà 5/5 Più di una settimana Idoneità per principianti 30/100
TimefoldAI/timefold-solver#2755 ·
I maintainer di solito rispondono entro 1 giorno
-
fix: Partitioned Search error with list variablesForse già presa @zepfred l’ha presa 2 giorni fa. Apertaprocess/needs triage
TimefoldAI/timefold-solver#2749 · 1 assegnatario ·
I maintainer di solito rispondono entro 1 giorno
-
Investigate constraint stream visualizationForse già presa @TomCools l’ha presa 6 giorni fa. Aperta
TimefoldAI/timefold-solver#2743 · 2 commenti · 1 assegnatario ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di TimefoldAI/timefold-solver
Issue simili
-
Wrong link to test resultsAperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
I maintainer di solito rispondono entro 2 giorni
-
docs(site): Mermaid edge-label contrast on Architecture and a table header on How it comparesApertadocumentation
Difficoltà 2/5 1-3 ore Idoneità per principianti 62/100
devops-thiago/ThrillhouseBot#1132 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 66/100
carlos-emr/carlos#4732 ·
I maintainer di solito rispondono entro 1 giorno
-
good first issue
Difficoltà 2/5 1-3 ore Idoneità per principianti 80/100
I maintainer di solito rispondono entro 3 giorni
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 66/100
I maintainer di solito rispondono entro 1 giorno