Please help with decoding key _id to primitive.ObjectID in go

Hello! I have that struct in go:

import (
	"go.mongodb.org/mongo-driver/bson/primitive"
)

type User struct {
	ID           primitive.ObjectID `json:"_id" bson:"_id,omitempty"`
	Username     string             `bson:"username"`
	PasswordHash string             `bson:"password_hash"`
	Permissions  Permissions        `json:"permissions" bson:"permissions"`
}

And I can’t decode *mongo.SingleResult into my type:
` usersCollection := mongoClient.Database(“test”).Collection(“users”)

user := auth.User{
	Username:     "anyuser",
	PasswordHash: "somehash",
	Permissions:  auth.NewPermissions(auth.PermissionUser),
}
if _, err := usersCollection.InsertOne(ctx, user); err != nil {
	panic(err)
}

singleResult := usersCollection.FindOne(ctx, bson.D{})
if singleResult.Err() != nil {
	panic(singleResult.Err())
}
var userResult auth.User
err = singleResult.Decode(&userResult)

It fails with:
panic: error decoding key _id: cannot decode objectID into an array

goroutine 1 [running]:
main.main()
./tmp.go:51 +0x505
exit status 2
`

Hi @Goshleg_N_A, which version of the Go Driver are you using?

Your issue is likely due to the way you’re inserting the document into MongoDB. Since the User struct has ID of type primitive.ObjectID, but you’re not explicitly setting it when inserting, MongoDB generates an _id field of type ObjectID automatically. However, your user struct lacks an ID field during insertion, which means MongoDB might be storing _id in an unexpected format.

Solution

1. Ensure ID is set before inserting

Modify the User struct instance before inserting it:

user := auth.User{
	ID:           primitive.NewObjectID(), // Generate a new ObjectID
	Username:     "anyuser",
	PasswordHash: "somehash",
	Permissions:  auth.NewPermissions(auth.PermissionUser),
}

This ensures that _id is stored as a primitive.ObjectID.

2. Use bson.M{} or bson.D{} for querying

Your query bson.D{} (empty filter) should work, but to be explicit, try:

singleResult := usersCollection.FindOne(ctx, bson.M{"username": "anyuser"})

This ensures you’re fetching a document that exists.

3. Check Decoding Again

After making the above changes, try decoding again:

var userResult auth.User
if err := singleResult.Decode(&userResult); err != nil {
	panic(err)
}
fmt.Println("User retrieved:", userResult)

Explanation of the Error

  • The error message cannot decode objectID into an array suggests that MongoDB might be returning an _id of a different type or an unexpected structure.
  • MongoDB automatically assigns an _id field as ObjectID when not explicitly set.
  • If you inserted a document without ID, MongoDB might be handling _id in a way that Go’s BSON decoding doesn’t expect.
1 Like

@Goshleg_N_A Is it possible you’re mixing Go Driver v1.x and v2.x packages? I was able to reproduce the error you’re seeing with this example:

package main

import (
	"context"

	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/v2/bson"
	"go.mongodb.org/mongo-driver/v2/mongo"
)

func main() {
	mongoClient := mongo.Connect()

	type User struct {
		ID           primitive.ObjectID `json:"_id" bson:"_id,omitempty"`
		Username     string             `bson:"username"`
		PasswordHash string             `bson:"password_hash"`
	}

	usersCollection := mongoClient.Database("test").Collection("users")

	ctx := context.TODO()
	user := User{
		Username:     "anyuser",
		PasswordHash: "somehash",
	}
	if _, err := usersCollection.InsertOne(ctx, user); err != nil {
		panic(err)
	}

	var userResult User
	err := usersCollection.FindOne(ctx, bson.D{}).Decode(&userResult)
	if err != nil {
		panic(err)
	}
}

Notice that primitive.ObjectID comes from the non-v2 package. Try changing that type to bson.ObjectID and see if it resolves your problem.

Thank you so much !! Had the same problem. Works ! :slight_smile: