Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)

I have created CmsNav entities, that are translateable, and also sit in some sort of hierarchical structure. Upon deleting a CmsNav by id, i get the following error, and i cannot seem to figure out whats going on. Perhaps someone can give some insight. thanks!

Future{cause=jakarta.persistence.OptimisticLockException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.bearden.cms.model.ui.CmsNavLang#10]}

CmsNav

@Entity
@Table(name = "cms_nav")
public class CmsNav extends Hierarchical {

  /* FIELDS */
  private Long id;
  private String link;
  private String target;                // _blank _self ...
  private String fontawesomeIcon;       // icon
  private boolean prioritizeSubmenu;    // in case of children, whether it will open the submenu, or function as a direct link itself.
  private CmsNavType cmsNavType;

  /* CONSTRUCTOR */
  public CmsNav() {
  }

  /* METHODS */

  /**
   * Sets the language for this translated class
   */
  @Transient
  public void setLang(Lang lang) {
    try {
      super.setLang(lang, CmsNavLang.class, this);
    } catch (TranslationNotFoundException e) {
      e.printStackTrace();
    }
  }

  public static CmsNav init(String link, String target, String fontawesomeIcon, boolean prioritizeSubmenu, CmsNavType cmsNavType, String label, Lang lang) {
    CmsNav cmsNav = new CmsNav();
    cmsNav.setLink(link);
    cmsNav.setTarget(target);
    cmsNav.setFontawesomeIcon(fontawesomeIcon);
    cmsNav.setPrioritizeSubmenu(prioritizeSubmenu);
    cmsNav.setCmsNavType(cmsNavType);
    CmsNavLang cmsNavLang = new CmsNavLang();
    cmsNavLang.setLabel(label);
    cmsNavLang.setTranslated(cmsNav);
    cmsNavLang.setLang(lang);
    cmsNav.addTranslation(cmsNavLang);
    return cmsNav;
  }

  @Override
  public Translation getUntranslated(Lang lang) {
    CmsNavLang cmsNavLang = new CmsNavLang();
    cmsNavLang.setId(-1L); // signals non-db entity
    cmsNavLang.setLabel(ConfigHolder.project_config.getJsonObject("framework").getString("missing_translation_text"));
    cmsNavLang.setLang(lang);
    return cmsNavLang;
  }


  /* GETTERS AND SETTERS */

  @OneToMany(mappedBy = "translated", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true, targetEntity = CmsNavLang.class)
  public List<Translation> getTranslations() {
    return super.getTranslations();
  }
  public void setTranslations(List<Translation> translations) {
    super.setTranslations(translations);
  }

  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "cms_nav_seq")
  @SequenceGenerator(name = "cms_nav_seq", sequenceName = "cms_nav_seq", allocationSize = 1)
  public Long getId() {
    return id;
  }

  public void setId(Long id) {
    this.id = id;
  }

  @Column(length = 255)
  public String getLink() {
    return link;
  }

  public void setLink(String link) {
    this.link = link;
  }

  @Column(length = 7)
  public String getTarget() {
    return target;
  }

  public void setTarget(String target) {
    this.target = target;
  }

  @Column(name = "prioritize_submenu")
  public boolean isPrioritizeSubmenu() {
    return prioritizeSubmenu;
  }

  public void setPrioritizeSubmenu(boolean prioritizeSubmenu) {
    this.prioritizeSubmenu = prioritizeSubmenu;
  }

  @Column(name = "fontawesome_icon", length = 30)
  public String getFontawesomeIcon() {
    return fontawesomeIcon;
  }

  public void setFontawesomeIcon(String fontawesomeIcon) {
    this.fontawesomeIcon = fontawesomeIcon;
  }

  @Enumerated(EnumType.STRING)
  @Column(length = 10, name = "cms_nav_type")
  public CmsNavType getCmsNavType() {
    return cmsNavType;
  }

  public void setCmsNavType(CmsNavType cmsNavType) {
    this.cmsNavType = cmsNavType;
  }

  @Transient
  public String getLabel() {
    return ((CmsNavLang) super.getActiveTranslation()).getLabel();
  }
  public void setLabel(String label) {
    ((CmsNavLang)super.getActiveTranslation()).setLabel(label);
  }
}

Hierarchical

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Hierarchical extends Translated {

  /* FIELDS */
  private Long id;
  private List<Hierarchical> children = new ArrayList<>();    // hierarchical children
  private Hierarchical parent;                                // (unless root node), this is the parent of this hierarchical

  /* CONSTRUCTOR */
  public Hierarchical(){
  }

  @Override
  public abstract Translation getUntranslated(Lang lang);

  /* METHODS */
  @Transient
  public void addChild(Hierarchical hierarchical){
    this.children.add(hierarchical);
  }

  @Transient
  public boolean hasChildren(){
     return !this.children.isEmpty();
  }


  /* GETTERS AND SETTERS */

  @OneToMany(mappedBy = "parent", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
  public List<Hierarchical> getChildren() {
    return children;
  }
  public void setChildren(List<Hierarchical> children) {
    this.children = children;
  }

  @ManyToOne()
  @JoinColumn(name = "parent_id", nullable = true)
  public Hierarchical getParent() {
    return parent;
  }
  public void setParent(Hierarchical parent) {
    this.parent = parent;
  }
  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "hierarchical_seq")
  @SequenceGenerator(schema = "public", name = "hierarchical_seq", sequenceName = "hierarchical_seq", allocationSize = 1)
  public Long getId() {
    return id;
  }

  public void setId(Long id) {
    this.id = id;
  }

}

Translated

@MappedSuperclass
public abstract class Translated {

  /* FIELDS */
  private List<Translation> translations = new ArrayList<>();
  private Translation activeTranslation;

  /* CONSTRUCTOR */
  public Translated() {

  }

  /* METHODS */
  /**
   * This abstract method enforces translated classes to provide a default translation object which is going to be
   * fallen back to in case the translated does not have a translation record present in the db for a certain language.
   */
  public abstract Translation getUntranslated(Lang lang);

  /**
   * Sets the active lang based on the provided lang object
   */
  @Transient
  public <T extends Translation> void setLang(Lang lang, Class<T> clazz, Translated self) throws TranslationNotFoundException {
    Optional<T> activeTranslation = this.translations.stream()
      .filter(translation -> clazz.isInstance(translation) && translation.getLang().equals(lang))
      .map(clazz::cast)
      .findFirst();
    if(activeTranslation.isPresent()){
        this.activeTranslation = activeTranslation.get();
    }
    else{
      Translation untranslated_translation = self.getUntranslated(lang);
      if(untranslated_translation != null){
        this.activeTranslation = untranslated_translation;
        this.translations.add(untranslated_translation);
        untranslated_translation.setTranslated(self);
      }else{
        throw new TranslationNotFoundException("No translation could be found for entity: ".concat(clazz.getName()));
      }
    }
  }

  /**
   * Adds a translation to this translated entity
   */
  @Transient
  public void addTranslation(Translation translation) {
    if(translation.getLang() != null){ // no lang indicates new lang record
      Optional<Translation> existingTranslation = this.translations.stream().filter(it -> it.getLang().getLangCode().equals(translation.getLang().getLangCode())).findFirst();
      if(existingTranslation.isPresent()){
        // Results in an overwrite
        this.translations.remove(existingTranslation.get());
      }
    }
    this.translations.add(translation);
  }

  /**
   * Retrieves the current translation
   */
  @Transient
  public Translation getActiveTranslation() {
    return this.activeTranslation;
  }

  /* GETTERS AND SETTERS */
  @Transient
  public List<Translation> getTranslations() {
    return translations;
  }
  public void setTranslations(List<Translation> translations) {
    this.translations = translations;
  }

}

CmsNavLang

@Entity
@Table(name = "cms_nav_lang")
public class CmsNavLang extends Translation {

  /* FIELDS */
  private Long id;
  private String label;        // nav label

  /* CONSTRUCTOR */
  public CmsNavLang(){
  }

  /* METHODS */

  /* GETTERS AND SETTERS */
  @ManyToOne(fetch = FetchType.LAZY, targetEntity = CmsNav.class)
  @JoinColumn(name="translated_id", nullable = false)
  public Translated getTranslated() {
    return super.getTranslated();
  }
  @Override
  public void setTranslated(Translated translated) {
    super.setTranslated(translated);
  }

  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "cms_nav_lang_seq")
  @SequenceGenerator(name = "cms_nav_lang_seq", sequenceName = "cms_nav_lang_seq", allocationSize = 1)
  public Long getId() {
    return id;
  }

  public void setId(Long id) {
    this.id = id;
  }

  @Column(length = 255)
  public String getLabel() {
    return label;
  }

  public void setLabel(String label) {
    this.label = label;
  }


}

Translation

@MappedSuperclass
public abstract class Translation {

  /* FIELDS */
  private Lang lang;
  private Translated translated; // the non-language dependant base class.

  /* CONSTRUCTOR */

  public Translation(){
  }

  public Translation(String langCode){
    this.lang = Lang.createLang(langCode);
  }

  /* METHODS */


  /* GETTERS AND SETTERS */
  @Convert(converter = LangConverter.class)
  @Column(length = 2)
  public Lang getLang() {
    return lang;
  }
  public void setLang(Lang lang) {
    this.lang = lang;
  }

  @Transient
  public Translated getTranslated() {
    return translated;
  }
  public void setTranslated(Translated translated) {
    this.translated = translated;
  }

}

Delete controller/repository

  public void deleteNav(RoutingContext routingContext) {
    PostBody postBody = PostBody.postBody(routingContext, true, false)
      .withLongPath("navId", true)
      .build();
    if(!postBody.hasErrors()){
      navRepository.deleteCmsNavById((postBody.getLong("navId"))).onComplete(deleteResult -> {
        if (deleteResult.succeeded() && deleteResult.result()) {
          ResponseUtil.ok(routingContext, "");
        }else if(deleteResult.failed()){
          ResponseUtil.internal_server_error(routingContext, deleteResult.cause().getMessage());
        }
      });
    }
  }
  public Future<Boolean> deleteCmsNavById(Long id) {
    CompletionStage<Boolean> deletionStage = super.getSessionFactory().withTransaction((session, transaction) -> {
      return session.find(CmsNav.class, id).thenCompose(cmsNav -> {
        if (cmsNav != null) {
          return session.remove(cmsNav).thenApply(v -> true);
        } else {
          return CompletableFuture.completedFuture(false);
        }
      });
    });
    return Future.fromCompletionStage(deletionStage);
  }

Do you use @Version somewhere in your model?

The exception usually tells you that an update failed, because the row didn’t exist in the table with the expected version. This can be due to another transaction deleting the row or updating it and hence incrementing the version to a higher value.
Or maybe the row simply never existed in the database, but you try to persist/merge it with a fixed id, even though the model says that property is generated.