Assertions don't survive reality
Usually assertions don't survive the contact with real world data. It's a part of the process of software engineering to decide, with which data you want to deal and which are out of scope.
Cyclic family graphs
Regarding family "trees" (in fact it are full blown graphs, including cycles), there is a nice anecdote:
I married a widow who had a grown daughter. My father, who often visited us, fell in love with my step-daughter and married her. As a result, my father became my son, and my daughter became my mother. Some time later, I gave my wife a son, who was the brother of my father, and my uncle. My father's wife (who is also my daughter and my mother) got a son. As a result, I got a brother and a grandson in the same person. My wife is now my grandmother, because she is my mother's mother. So I am the husband of my wife, and at the same time the step-grandson of my wife. In other words, I'm my own grandpa.
Things get even more strange, when you take surrogates or "fuzzy fatherhood" into account.
How to deal with that
Define cycles as out-of-scope
You could decide that your software should not deal with such rare cases. If such a case occurs, the user should use a different product. This makes dealing with the more common cases much more robust, because you can keep more assertions and a simpler data model.
In this case, add some good import and export features to your software, so the user can easily migrate to a different product when necessary.
Allow manual relations
You could allow the user to add manual relations. These relations are not "first-class citizens", i.e. the software takes them as-is, doesn't check them and doesn't handle them in the main data model.
The user can then handle rare cases by hand. Your data model will still stay quite simple and your assertions will survive.
Be careful with manual relations. There is a temptation to make them completely configurable and hence create a fully configurable data model. This will not work: Your software will not scale, you will get strange bugs and finally the user interface will become unusable. This anti-pattern is called "soft coding", and "The daily WTF" is full of examples for that.
Make your data model more flexible, skip assertions, test invariants
The last resort would be making your data model more flexible. You would have to skip nearly all assertions and base your data model on a full blown graph. As the above example shows, it is easily possible to be your own grandfather, so you can even have cycles.
In this case, you should extensively test your software. You had to skip nearly all assertions, so there is a good chance for additional bugs.
Use a test data generator to check unusual test cases. There are quick check libraries for Haskell, Erlang or C. For Java / Scala there are ScalaCheck and Nyaya. One test idea would be to simulate a random population, let it interbreed at random, then let your software first import and then export the result. The expectation would be, that all connections in the output are also in the input and vice verse.
A case, where a property stays the same is called an invariant. In this case, the invariant is the set of "romantic relations" between the individuals in the simulated population. Try to find as much invariants as possible and test them with randomly generated data. Invariants can be functional, e.g.:
- an uncle stays an uncle, even when you add more "romantic relations"
- every child has a parent
- a population with two generations has at least one grand-parent
Or they can be technical:
- Your software will not crash on a graph up to 10 billion members (no matter how many interconnections)
- Your software scales with O(number-of-nodes) and O(number-of-edges^2)
- Your software can save and re-load every family graph up to 10 billion members
By running the simulated tests, you will find lots of strange corner cases. Fixing them will take a lot of time. Also you will lose a lot of optimizations, your software will run much slower. You have to decide, if it is worth it and if this is in the scope of your software.