flowable/flowable-engine · error · FlowableObjectNotFoundException

Could not find a plan item instance with id '${planItemInsta

Error message

Could not find a plan item instance with id '${planItemInstanceId}'.

What it means

FlowableObjectNotFoundException thrown when no historic plan item instance matches the supplied planItemInstanceId. The GET endpoint on /cmmn-history/historic-planitem-instances/{id} looks up the instance via HistoricPlanItemInstanceQuery and fails when singleResult() is null.

Source

Thrown at modules/flowable-cmmn-rest/src/main/java/org/flowable/cmmn/rest/service/api/history/planitem/HistoricPlanItemInstanceResource.java:45

import io.swagger.annotations.Authorization;

/**
 * @author Tijs Rademakers
 * @author Dennis Federico
 */
@RestController
@Api(tags = {"History PlanItem"}, authorizations = {@Authorization(value = "basicAuth")})
public class HistoricPlanItemInstanceResource extends HistoricPlanItemInstanceBaseResource {

    @ApiOperation(value = "Get a historic plan item instance", tags = {"History PlanItem"}, nickname = "getHistoricPlanItemInstance")
    @ApiResponses(value = {
            @ApiResponse(code = 200, message = "Indicates that the historic plan item instances could be found."),
            @ApiResponse(code = 404, message = "Indicates that the historic plan item instances could not be found.")})
    @GetMapping(value = "/cmmn-history/historic-planitem-instances/{planItemInstanceId}", produces = "application/json")
    public HistoricPlanItemInstanceResponse getPlanItemInstance(@ApiParam(name = "planItemInstanceId") @PathVariable String planItemInstanceId) {
        HistoricPlanItemInstance planItemInstance = historyService.createHistoricPlanItemInstanceQuery().planItemInstanceId(planItemInstanceId).singleResult();
        if (planItemInstance == null) {
            throw new FlowableObjectNotFoundException("Could not find a plan item instance with id '" + planItemInstanceId + "'.", HistoricPlanItemInstance.class);
        }
        
        if (restApiInterceptor != null) {
            restApiInterceptor.accessHistoryPlanItemInfoById(planItemInstance);
        }
        
        return restResponseFactory.createHistoricPlanItemInstanceResponse(planItemInstance);
    }

}

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Validate the planItemInstanceId against the list endpoint /cmmn-history/historic-planitem-instances filtered by caseInstanceId.
  2. Catch FlowableObjectNotFoundException and return 404 to the API consumer.
  3. Check history cleanup job configuration/retention times.
  4. Ensure CMMN history level (e.g. 'full') records plan item instances.
  5. Confirm the request targets the correct Flowable engine/database.

Example fix

// before
var item = client.getPlanItem(id);
// after
try {
    var item = client.getPlanItem(id);
} catch (FlowableObjectNotFoundException e) {
    return ResponseEntity.notFound().build();
}
Defensive patterns

Strategy: try-catch

Try / catch

try {
    HistoricPlanItemInstanceResponse p = getPlanItem(id);
} catch (FlowableObjectNotFoundException e) {
    return ResponseEntity.notFound().build();
}

Prevention

When it happens

Trigger: GET /cmmn-history/historic-planitem-instances/{planItemInstanceId} with an id that does not exist, was purged by history cleanup, or belongs to another tenant/engine datasource.

Common situations: Casing/typo errors in the id; plan item history not recorded because history level is too low; records removed by the Flowable history cleaner after retention expired; ids copied from a test environment.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/656fe62783894acc. Report an issue: GitHub.