Invalid assignment of property or key ‘texture’ with value of type ‘CompressedTexture2D’

Godot Version

Godot Engine v4.4

Question

Hi there, I’m doing an inventory system for a point & click adventure, and I stumbled upon this error: “Invalid assignment of property or key ‘texture’ with value of type ‘CompressedTexture2D’ on a base object of type ‘Nil’.”
I’m just trying to assign a texture picked from an @export var of type Resource to a Sprite2D.texture (of course the var is already set on the object in the 2d environment).

Inventory item resource code:

class_name InventoryItem
extends Resource

@export var item_name : String
@export var item_sprite : Texture2D

Inventory slot code:

class_name InventorySlot
extends Panel

@onready var sprite: Sprite2D = $Sprite2D

func update_slot(item : InventoryItem):
	sprite.texture = item.item_sprite

Inventory code:

extends Control

@onready var anim_player: AnimationPlayer = $AnimationPlayer
@onready var background: ColorRect = $ColorRect
@onready var slots_container: HBoxContainer = $ColorRect/HBoxContainer

func _ready() -> void:
	background.position.y = -100.0

func _on_area_mouse_entered() -> void:
	anim_player.play("inventory_appearance")

func _on_area_mouse_exited() -> void:
	anim_player.play_backwards("inventory_appearance")
	
func add_slot(item_slot):
	slots_container.add_child(item_slot)

Pick-up function call on Player:

func pick_up():
	GameManager.enable_input = true
	GameManager.dialogue_player.update_dialogue(GameManager.pickup_text)
	state = NONE
	var slot_to_add = InventorySlot.new()
	GameManager.inventory.add_slot(slot_to_add)
	slot_to_add.update_slot(GameManager.item_to_pick)
	print("picked up")

I’m assuming the error was in this code:

@onready var sprite: Sprite2D = $Sprite2D

func update_slot(item: InventoryItem):
    sprite.texture = item.item_sprite

I bet if you check, sprite is nil. It could be because $Sprite2D isn’t created yet at this point, or it could be that $Sprite2D isn’t actually a valid node path. Godot doesn’t notice whether a path is valid until you actually try to use the result, and if the path is bad you get nil.

Is the sprite actually called Sprite2D in the node hierarchy, or did you perhaps rename it? Is it a child node of this node? If you have something like:

Scene (node2d) # script attached here
  Panel (container)
    Sprite (sprite2d)

You need to address that with $Panel/Sprite, not just $Sprite.

I imagined the problem was the Sprite2D. I tried to print the item_name of the resource var instead of assigning the texture, just for debugging, and this is also what I got on log:

inventory_slot.gd:4 @ @implicit_ready(): Node not found: "Sprite2D" (relative to "/root/GameManager/Inventory/ColorRect/HBoxContainer/@Panel@2").

I didn’t rename the Sprite2D node, this is the structure:

InventorySlot (Panel) #root
  Sprite2D (Sprite2D)

When using the shortcut (ctrl + drag) on the Sprite2D node to create the @onready var, Godot automatically writes that as $Sprite2D. I’ve tried to write that as $InventorySlot/Sprite2D, and also to put a Node2D as the root (and assigning the script to it), but still the same error.

Is your script attached to InventorySlot?

Maybe try:

func update_slot(item: InventoryItem):
    get_node("Sprite2D").texture = item.item_sprite

In the same function I’d suggest temporarily adding:

func _ready():
    print_tree_pretty()

That will let you know what the node hierarchy looks like from that file.

Yes, the script is attached to InventorySlot.
I’ve just tried the get_node("Sprite2D"), still the same error, and with the print_tree_pretty() I got this:

 ┖╴@Panel@2

So I guess no Sprite2D node is printed. I’ve also tried to replace it with TextureRect, but it brings the same result.
I don’t understand, it really bugs me.

I’m assuming that @Panel@2 is InventorySlot being a subclass of Panel.

It doesn’t look like there’s a sprite attached at all. Either it wasn’t there to begin with, or something is deleting it.

You could make a sprite, if you wanted:

func update_slot(item: InventoryItem):
    var sprite: Sprite2D = get_node_or_null("InventoryIcon")
    if !is_instance_valid(sprite): # Do we need to create it?
        sprite      = Sprite2D.new()
        sprite.name = "InventoryIcon"
        # set anything else you need to; position, self_modulate...
        add_child(sprite)
    sprite.texture = item.item_sprite

That works!
I guess it’ll remain a mistery why the Sprite2D kept disappearing, but I’ll use this solution now and set the parameters I need for the Sprite2D directly in the function. Thank you!

1 Like