pocketbase/pocketbase · error

expected map or array, got %#v

Error message

expected map or array, got %#v

What it means

extractNestedVal walked a key path into a JSON value whose current node is neither a map nor an array (e.g. a string or number), so the remaining path segments cannot be applied. The message prints the offending value with %#v, showing exactly what was found instead.

Source

Thrown at core/record_field_resolver.go:540

		return arrVal(m, keys...)
	case []uint16:
		return arrVal(m, keys...)
	case []uint32:
		return arrVal(m, keys...)
	case []uint64:
		return arrVal(m, keys...)
	case []mapExtractor:
		extracted := make([]any, len(m))
		for i, v := range m {
			extracted[i] = v.AsMap()
		}
		return arrVal(extracted, keys...)
	case []any:
		return arrVal(m, keys...)
	case []types.JSONRaw:
		return arrVal(m, keys...)
	default:
		return nil, fmt.Errorf("expected map or array, got %#v", rawData)
	}
}

func mapVal[T any](m map[string]T, keys ...string) (any, error) {
	result, ok := m[keys[0]]
	if !ok {
		return nil, fmt.Errorf("invalid key path - missing key %q", keys[0])
	}

	// end key reached
	if len(keys) == 1 {
		return result, nil
	}

	return extractNestedVal(result, keys[1:]...)
}

func arrVal[T any](m []T, keys ...string) (any, error) {

View on GitHub (pinned to 5d217ddb50)

Solutions

  1. Inspect the printed value — it tells you the actual type at that path; adjust the filter path to match the real structure.
  2. Normalize the stored data so the path has a consistent shape in every row (migration over the json column).
  3. Guard heterogeneous fields by first filtering on a stable part (e.g. type discriminator) before the nested path.

Example fix

// before: tags sometimes stored as string
filter := "meta.tags.name = 'x'"
// after: normalize data so tags is always an array of objects, then keep the filter
Defensive patterns

Strategy: type-guard

Type guard

func isMapOrArray(v any) bool {
    switch v.(type) {
    case map[string]any, []any:
        return true
    }
    return false
}

Try / catch

if err != nil && strings.Contains(err.Error(), "expected map or array") {
    // the %#v in the message shows the actual value — align the filter path with the real shape
}

Prevention

When it happens

Trigger: Filter like "meta.tags.name = 'x'" where meta.tags is a plain string in some rows (not an array of objects), or "settings.theme.dark = true" where settings.theme is the boolean true.

Common situations: Heterogeneous json field content across rows (some rows store a scalar where others store an object); schema evolved inside a schemaless json field; filter authored against an example row that is not representative.

Related errors


AI-assisted analysis of pocketbase/pocketbase@5d217ddb50 (2026-08-15). Data as JSON: /api/errors/c5ed81117aae6861. Report an issue: GitHub.