Skip to content

Map literals do not reject duplicate keys #1348

Description

@HegzaPlacx

A map literal that contains duplicate keys is evaluated without error; the last value silently wins, instead of failing as the spec requires.

{1: "a", 1: "b"}         // -> {1: "b"}, no error
{"k": "x", "k": "y"}     // -> {"k": "y"}, no error
{1: "a", 1: "c", 1: "d"} // -> {1: "d"}, no error

The language spec ("Aggregate Values" in langdef) states: "It is an error to have duplicate keys or field names." These expressions should fail with an evaluation error.

This is also inconsistent within cel-go itself. The comprehension path reports the same collision:

{"a": 1, "b": 1}.transformMapEntry(k, v, {v: k})
// error: insert failed: key 1 already exists

mutableMap.Insert (common/types/map.go) detects existing keys using CEL equality, but the map-literal evaluation path (evalMap.Exec in interpreter/interpretable.go) writes into a plain Go map[ref.Val]ref.Val and never checks for duplicates.

Keys are not necessarily constant — they can be computed at runtime (e.g. {("rol" + "e"): "admin", "role": "guest"} evaluates to {"role": "guest"}), so the duplicate is not always visible in the source text or to the type checker.

For comparison, cel-cpp and cel-java both reject duplicate keys (cel-cpp returns a DuplicateKeyError unconditionally; cel-java enables errorOnDuplicateMapKeys by default), so the same expression behaves differently across implementations.

Suggested fix: detect duplicate keys in the map-literal evaluation path using CEL equality, the same way mutableMap.Insert already does, and return an evaluation error.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions