pocketbase/pocketbase · error
[geoDistance] argument %d must be an identifier or number
Error message
[geoDistance] argument %d must be an identifier or number
What it means
Validation error from `geoDistance`: each of the 4 arguments must be a filter-expr identifier (column reference) or a number token. Text literals, booleans, or other token types are rejected before resolution, because coordinates must map to numeric SQL values.
Source
Thrown at tools/search/token_functions.go:36
// distance between 2 points in kilometres (https://www.movable-type.co.uk/scripts/latlong.html).
//
// The accepted arguments at the moment could be either a plain number or a column identifier (including NULL).
// If the column identifier cannot be resolved and converted to a numeric value, it resolves to NULL.
//
// Similar to the built-in SQLite functions, geoDistance doesn't apply
// a "match-all" constraints in case there are multiple relation fields arguments.
// Or in other words, if a collection has "orgs" multiple relation field pointing to "orgs" collection that has "office" as "geoPoint" field,
// then the filter: `geoDistance(orgs.office.lon, orgs.office.lat, 1, 2) < 200`
// will evaluate to true if for at-least-one of the "orgs.office" records the function result in a value satisfying the condition (aka. "result < 200").
"geoDistance": func(argTokenResolverFunc func(fexpr.Token) (*ResolverResult, error), args ...fexpr.Token) (*ResolverResult, error) {
if len(args) != 4 {
return nil, fmt.Errorf("[geoDistance] expected 4 arguments, got %d", len(args))
}
resolvedArgs := make([]*ResolverResult, 4)
for i, arg := range args {
if arg.Type != fexpr.TokenIdentifier && arg.Type != fexpr.TokenNumber {
return nil, fmt.Errorf("[geoDistance] argument %d must be an identifier or number", i)
}
resolved, err := argTokenResolverFunc(arg)
if err != nil {
return nil, fmt.Errorf("[geoDistance] failed to resolve argument %d: %w", i, err)
}
resolvedArgs[i] = resolved
}
lonA := resolvedArgs[0].Identifier
latA := resolvedArgs[1].Identifier
lonB := resolvedArgs[2].Identifier
latB := resolvedArgs[3].Identifier
return &ResolverResult{
NullFallback: NullFallbackDisabled,
Identifier: `(6371 * acos(` +
`cos(radians(` + latA + `)) * cos(radians(` + latB + `)) * ` +
`cos(radians(` + lonB + `) - radians(` + lonA + `)) + ` +View on GitHub (pinned to 5d217ddb50)
Solutions
- Remove quotes around field identifiers: `office.lon`, not `'office.lon'`
- Express fixed coordinates as bare numbers, e.g. `26.0984`
- Use only direct column references or numeric literals for all 4 arguments
Example fix
// before
filter := "geoDistance('office.lon', 'office.lat', 26.1, 24.2) < 200"
// after
filter := "geoDistance(office.lon, office.lat, 26.1, 24.2) < 200" Defensive patterns
Strategy: validation
Validate before calling
// ensure geoDistance args are bare identifiers or numbers
for _, a := range args {
if !regexp.MustCompile(`^-?\d+(\.\d+)?$`).MatchString(a) && !isIdentifierToken(a) {
return fmt.Errorf("geoDistance arg %q must be an identifier or number", a)
}
} Type guard
null
Try / catch
if err != nil && strings.Contains(err.Error(), "[geoDistance] argument") && strings.Contains(err.Error(), "must be an identifier or number") {
return apiError400("geoDistance arguments must be unquoted field paths or numeric literals")
} Prevention
- Never quote coordinate field paths in filters (office.lon, not 'office.lon')
- Pass fixed coordinates as bare numbers
- Document the filter grammar for clients building geoDistance filters
When it happens
Trigger: Passing a quoted string as a coordinate, e.g. `geoDistance('office.lon', office.lat, 1, 2)`; passing a boolean or another function call as an argument.
Common situations: Quoting field paths out of habit from JSON usage; passing dynamic text values instead of numbers; confusion about identifier vs. literal syntax in the filter language.
Related errors
- [geoDistance] expected 4 arguments, got %d
- [strftime] expected at least 1 arguments, got %d
- invalid left operand %q - %v
- invalid right operand %q - %v
- unknown function %q
AI-assisted analysis of pocketbase/pocketbase@5d217ddb50 (2026-08-15).
Data as JSON: /api/errors/e26f768ebfea0e25.
Report an issue: GitHub.