greenrobot/greenDAO · error · RuntimeException

Source entity has no primary key, but we need it for

Error message

Source entity has no primary key, but we need it for 

What it means

ToMany.init2ndPass() requires the source entity of a to-many relation to have a primary key, because the generated join query filters target rows by the source entity's PK columns. When sourceProperties was not explicitly set and the source entity has no PK properties, the generator aborts with this RuntimeException naming the relation.

Solutions

  1. Add a primary key to the source entity (e.g. entity.addIdProperty().primaryKey())
  2. Explicitly set source properties for the relation via toMany.setSourceProperties(...) matching target properties
  3. If the source table genuinely has no PK, add one (even a composite or synthetic column) before generating
  4. Verify entity.getPropertiesPk() returns the intended PK by checking the entity definition

Example fix

// before
Entity user = schema.addEntity("User"); // no PK
Entity note = schema.addEntity("Note");
user.addToMany(note, note.getUserId());
// after
Entity user = schema.addEntity("User");
user.addIdProperty().primaryKey();
user.addToMany(note, note.getUserId());
Defensive patterns

Strategy: validation

Validate before calling

if (sourceEntity.getPropertiesPk().isEmpty()) throw new IllegalStateException("Source entity needs a PK before addToMany");

Type guard

function hasPk(entity) { return entity != null && entity.getPkProperty() != null; }

Try / catch

try { schema.generate(); } catch (RuntimeException e) { if (e.getMessage().startsWith("Source entity has no primary key")) { fixSchemaDefinition(e.getMessage()); } else { throw e; } }

Prevention

When it happens

Trigger: Creating a ToMany relation (entity.addToMany) where the source entity defines no primary key and no explicit sourceProperties are supplied via setSourceProperties/setOrderBy.

Common situations: Generating an entity from a legacy table without a primary key; forgetting .primaryKey() on the source entity's id property; schema copied from a NoSQL design into greenDAO.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of greenrobot/greenDAO@0bbb338e17 (2026-09-08). Data as JSON: /api/errors/8abdfb0399dccab2. Report an issue: GitHub.

Appendix: source

Thrown at DaoGenerator/src/org/greenrobot/greendao/generator/ToMany.java:53

    public Property[] getSourceProperties() {
        return sourceProperties;
    }

    public void setSourceProperties(Property[] sourceProperties) {
        this.sourceProperties = sourceProperties;
    }

    public Property[] getTargetProperties() {
        return targetProperties;
    }

    void init2ndPass() {
        super.init2ndPass();
        if (sourceProperties == null) {
            List<Property> pks = sourceEntity.getPropertiesPk();
            if (pks.isEmpty()) {
                throw new RuntimeException("Source entity has no primary key, but we need it for " + this);
            }
            sourceProperties = new Property[pks.size()];
            sourceProperties = pks.toArray(sourceProperties);
        }
        int count = sourceProperties.length;
        if (count != targetProperties.length) {
            throw new RuntimeException("Source properties do not match target properties: " + this);
        }

        for (int i = 0; i < count; i++) {
            Property sourceProperty = sourceProperties[i];
            Property targetProperty = targetProperties[i];

            PropertyType sourceType = sourceProperty.getPropertyType();
            PropertyType targetType = targetProperty.getPropertyType();
            if (sourceType == null || targetType == null) {
                throw new RuntimeException("Property type uninitialized");
            }

View on GitHub (pinned to 0bbb338e17)