I did some digging through ldpc=2.2.8, and I think I found your problem.
The main difference between the experiment with rounds=1 and rounds>1 is that some lines of the form error(0.01) D0 D1 ^ D2 appear in the latter cases while none appears in the former case. This means something has gone wrong in the handling of the decomposed errors.
We will focus on the following small snippet that fails in the exact same manner as yours:
import stim
import pymatching
from ldpc.ckt_noise import detector_error_model_to_check_matrices as dem_to_check
dem = stim.DetectorErrorModel("""
error(0.01) D0 D1 ^ D5 D6
error(0.02) D0 D2 ^ D5 D7
""")
dem2 = dem_to_check(dem)
check_matrix, observable_matrix, priors = dem2.check_matrix, dem2.observables_matrix, dem2.prior
matching = pymatching.Matching.from_check_matrix(check_matrix, error_probabilities=priors)
The return value of detector_error_model_to_check_matrices is a DemMatrices object from which you only extracted three fields: check_matrix, observable_matrix and priors.
By looking at how they are defined, we can learn that they handle the case where decomposed errors are not decomposed but remain as hyperedges (hence the "more than 2 ones per column" error from pymatching).
Two others fields exist and should give you the decomposed errors as edges: edge_check_matrix and edge_observables_matrix. However, merely using these fields is not enough:
import stim
import pymatching
from ldpc.ckt_noise import detector_error_model_to_check_matrices as dem_to_check
dem = stim.DetectorErrorModel("""
error(0.01) D0 D1 ^ D5 D6
error(0.02) D0 D2 ^ D5 D7
""")
dem2 = dem_to_check(dem)
check_matrix, observable_matrix, priors = dem2.edge_check_matrix, dem2.edge_observables_matrix, dem2.prior
matching = pymatching.Matching.from_check_matrix(check_matrix, error_probabilities=priors)
This now fails because the priors array is not coherent with the new matrices. There is no "edge_priors" in the DemMatrices class, so we will need to compute it ourselves using yet another of its field: hyperedge_to_edge_matrix.
import stim
import pymatching
from ldpc.ckt_noise import detector_error_model_to_check_matrices as dem_to_check
dem = stim.DetectorErrorModel("""
error(0.01) D0 D1 ^ D5 D6
error(0.02) D0 D2 ^ D5 D7
""")
dem2 = dem_to_check(dem)
check_matrix, observable_matrix, priors = dem2.edge_check_matrix, dem2.edge_observables_matrix, dem2.priors
edge_priors = dem2.hyperedge_to_edge_matrix @ priors
matching = pymatching.Matching.from_check_matrix(check_matrix, error_probabilities=edge_priors)
You can look at any sparse matrix with the todense method. From what I gathered, hyperedge_to_edge_matrix stores in its columns which edges correspond to each hyperedge, so I think the matrix product I used for edge_priors works to determine the correct prior probability of each edge.
Coming back to your stim experiment, it does not raise any error anymore, although I did not try to run it beyond this point:
import stim
import pymatching
from ldpc.ckt_noise import detector_error_model_to_check_matrices as dem_to_check
p = 0.01
d=3
circuit = stim.Circuit.generated('surface_code:rotated_memory_z',
after_clifford_depolarization=p,
after_reset_flip_probability=p,
before_measure_flip_probability=p,
before_round_data_depolarization=p,
distance=d,
rounds=2)
dem = circuit.detector_error_model(decompose_errors=True)
dem2 = dem_to_check(dem)
check_matrix, observable_matrix, priors = dem2.edge_check_matrix, dem2.edge_observables_matrix, dem2.priors
edge_priors = dem2.hyperedge_to_edge_matrix @ priors
matching = pymatching.Matching.from_check_matrix(check_matrix, error_probabilities=edge_priors)