{"record":{"id":"027422377a6f764f","repo":"hibernate/hibernate-orm","slug":"index-operator-applied-to-non-plural-path-getna","errorCode":null,"errorMessage":"Index operator applied to non-plural path '${getNavigablePath()}'","messagePattern":"Index operator applied to non-plural path '(.+?)'","errorType":"exception","errorClass":"SemanticException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/domain/SqmPath.java","lineNumber":144,"sourceCode":"\t\tfinal var lhs = getLhs();\n\t\tif ( lhs != null ) {\n\t\t\treturn lhs.findRoot();\n\t\t}\n\n\t\tthrow new ParsingException( \"Could not find root\" );\n\t}\n\n\tSqmPath<?> resolvePathPart(\n\t\t\tString name,\n\t\t\tboolean isTerminal,\n\t\t\tSqmCreationState creationState);\n\n\t@Override\n\tdefault SqmPath<?> resolveIndexedAccess(\n\t\t\tSqmExpression<?> selector,\n\t\t\tboolean isTerminal,\n\t\t\tSqmCreationState creationState) {\n\t\tthrow new SemanticException( \"Index operator applied to non-plural path '\" + getNavigablePath() + \"'\" );\n\t}\n\n\t/**\n\t * Get this path's actual resolved model, i.e. the concrete type for generic attributes.\n\t */\n\tSqmPathSource<T> getResolvedModel();\n\n\t// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\t// Covariant overrides\n\n\t@Nonnull\n\t@Override\n\t<Y> SqmPath<Y> get(@Nonnull SingularAttribute<? super T, Y> attribute);\n\n\t@Nonnull\n\t@Override\n\t<E, C extends Collection<E>> SqmPluralPath<C,E> get(@Nonnull PluralAttribute<? super T, C, E> collection);\n","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/domain/SqmPath.java#L126-L162","documentation":"In HQL, `path[selector]` (indexed access) is dispatched by SemanticQueryBuilder.visitIndexedPathAccessFragment (SemanticQueryBuilder.java:5840) to SqmPath.resolveIndexedAccess. Only plural paths - list/map attributes via SqmPluralValuedSimplePath, plus function paths - implement it; the SqmPath default throws SemanticException('Index operator applied to non-plural path \\'<navigablePath>\\'') naming the exact offending path. It means the [] operator was applied to a singular attribute (basic value, embeddable, or single-valued association).","triggerScenarios":"Any HQL path expression with an index on a non-plural attribute: `where p.name[1] = 'B'` (String attribute), `select e.address[0]` (embeddable), `p.contact[0]` (singular association); also typos where a similarly named singular attribute resolves instead of the intended List/Map attribute.","commonSituations":"Assuming HQL supports Java-style String/array indexing; migrating native SQL with array subscripts to HQL; an attribute refactored from List<X> to X (or renamed) leaving stale HQL; JSON-style access attempts on basic columns.","solutions":["Use [] only on List- or Map-valued plural attributes (@ElementCollection, @OneToMany/@ManyToMany)","For strings, use substring()/like instead of name[1]","Check the attribute spelling - the intended plural attribute may have a different name","Map the data as a real collection (e.g. @ElementCollection List) or use JSON functions if the column holds JSON"],"exampleFix":"// before - name is a singular String attribute\nselect p from Person p where p.name[1] = 'B'\n\n// after - use string functions on singular attributes\nselect p from Person p where substring( p.name, 1, 1 ) = 'B'","handlingStrategy":"validation","validationCode":"import jakarta.persistence.metamodel.*;\n\nAttribute<?, ?> attr = entityManager.getMetamodel()\n        .entity( Person.class )\n        .getAttribute( attributeName );\nif ( !(attr instanceof ListAttribute || attr instanceof MapAttribute) ) {\n    throw new IllegalArgumentException(\n            \"Cannot apply [] to '\" + attributeName + \"': not a List/Map attribute\" );\n}\n// safe to emit: path[...] or path[index]","typeGuard":"static boolean isIndexable(Attribute<?, ?> attribute) {\n    return attribute instanceof jakarta.persistence.metamodel.ListAttribute<?, ?>\n        || attribute instanceof jakarta.persistence.metamodel.MapAttribute<?, ?, ?>;\n}","tryCatchPattern":"try {\n    return session.createQuery( hql, Person.class ).list();\n} catch ( org.hibernate.query.SemanticException e ) {\n    if ( e.getMessage() != null && e.getMessage().startsWith( \"Index operator applied to non-plural path\" ) ) {\n        throw new IllegalArgumentException( \"HQL uses [] on a singular attribute: \" + hql, e );\n    }\n    throw e;\n}","preventionTips":["Reserve the [] operator for List- and Map-valued attributes","Validate dynamically built HQL fragments against the metamodel before execution","Use substring()/like for string character access","Keep HQL in sync when attributes change between singular and plural","Prefer criteria API for dynamic paths - type errors surface at compile time"],"tags":["hibernate","hql","sqm","indexed-access","collections","semantic-error"],"backgroundTag":"hql-index-operator-non-plural-path","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}