Quick answer: In Godot 4, set_shader_param() was renamed to set_shader_parameter(). The old method name from Godot 3.x no longer exists. Update your code to use material.set_shader_parameter('uniform_name', value) instead of material.set_shader_param('uniform_name', value).

Here is how to fix Godot shader uniform not updating GDScript. You declared a uniform in your shader, set its value from GDScript, and nothing changes. The shader keeps using the default value no matter what you pass in. This is one of the most common migration issues when moving from Godot 3 to Godot 4, and it has two distinct causes: the renamed API method and shared material resources.

The Symptom

You have a shader with a uniform declaration and you try to set it from GDScript:

# Your shader declares this uniform
# uniform float dissolve_amount : hint_range(0.0, 1.0) = 0.0;

# Your GDScript tries to set it
material.set_shader_param("dissolve_amount", 0.5)
# Nothing happens. The dissolve_amount stays at 0.0.

You see one or more of these issues:

What Causes This

Cause 1: Renamed API in Godot 4. In Godot 3.x, the method was called set_shader_param() and get_shader_param(). In Godot 4.x, these were renamed to set_shader_parameter() and get_shader_parameter(). The old method names no longer exist. If you are following a Godot 3 tutorial or migrating an existing project, this is the most likely cause.

Cause 2: Shared material resources. When you assign a material in the Godot editor, multiple nodes can reference the same ShaderMaterial resource. If you set a uniform value on one node’s material, it changes for all nodes sharing that material. Conversely, if you think you are setting a unique value but it keeps being overwritten, another node or script may be setting the same shared material’s uniform to a different value on the same frame.

Cause 3: Uniform name mismatch. Uniform names are case-sensitive and must match exactly. If your shader declares uniform float dissolve_Amount but your GDScript calls set_shader_parameter("dissolve_amount", ...), the parameter silently fails because the names do not match. Godot does not warn you about setting a non-existent uniform—it just does nothing.

The Fix

Step 1: Use the Godot 4 API. Replace all set_shader_param calls with set_shader_parameter:

extends Sprite2D

func _ready():
  # WRONG (Godot 3 API - will error in Godot 4)
  # material.set_shader_param("dissolve_amount", 0.5)

  # CORRECT (Godot 4 API)
  material.set_shader_parameter("dissolve_amount", 0.5)

func _process(delta):
  # Animate the uniform over time
  var t = fmod(Time.get_ticks_msec() / 1000.0, 2.0) / 2.0
  material.set_shader_parameter("dissolve_amount", t)

Step 2: Make the material unique per instance. If you need different uniform values on different nodes that share the same scene or material resource, you must duplicate the material:

extends Sprite2D

func _ready():
  # Duplicate the material so changes only affect this node
  material = material.duplicate()

  # Now this only affects this specific sprite
  material.set_shader_parameter("dissolve_amount", 0.5)

Alternatively, you can set this in the editor: select the material resource in the inspector, click the resource dropdown, and enable Resource → Local to Scene. This automatically creates a unique copy of the material for each instance of the scene.

Step 3: Verify uniform names match exactly. Print the available parameters to debug name mismatches:

extends Sprite2D

func _ready():
  var shader_mat = material as ShaderMaterial
  if shader_mat and shader_mat.shader:
    var params = shader_mat.shader.get_shader_uniform_list()
    for param in params:
      print("Uniform: ", param.name, " Type: ", param.type)

  # Now set with the exact name from the output above
  material.set_shader_parameter("dissolve_amount", 0.5)

Step 4: Complete example with a dissolve shader. Here is a full working dissolve effect with proper GDScript integration:

// dissolve.gdshader
shader_type canvas_item;

uniform float dissolve_amount : hint_range(0.0, 1.0) = 0.0;
uniform sampler2D noise_texture;
uniform vec4 edge_color : source_color = vec4(1.0, 0.5, 0.0, 1.0);
uniform float edge_width : hint_range(0.0, 0.2) = 0.05;

void fragment() {
  vec4 tex = texture(TEXTURE, UV);
  float noise = texture(noise_texture, UV).r;

  float edge = smoothstep(
    dissolve_amount - edge_width,
    dissolve_amount,
    noise
  );

  COLOR = mix(edge_color * tex.a, tex, edge);
  COLOR.a *= step(dissolve_amount, noise + edge_width);
}
# dissolve_sprite.gd
extends Sprite2D

@export var dissolve_duration: float = 1.5
var dissolve_progress: float = 0.0
var is_dissolving: bool = false

func _ready():
  # Make material unique so each instance dissolves independently
  material = material.duplicate()

func start_dissolve():
  is_dissolving = true
  dissolve_progress = 0.0

func _process(delta):
  if not is_dissolving:
    return

  dissolve_progress += delta / dissolve_duration
  dissolve_progress = min(dissolve_progress, 1.0)

  material.set_shader_parameter("dissolve_amount", dissolve_progress)

  if dissolve_progress >= 1.0:
    is_dissolving = false
    queue_free()

Why This Works

The set_shader_parameter() method writes a value to the ShaderMaterial’s parameter override map. When the rendering server processes the draw call for that node, it reads these overrides and passes them to the GPU as uniform values. The rename from set_shader_param to set_shader_parameter was part of Godot 4’s API consistency cleanup—many abbreviated method names were expanded to their full forms.

The material uniqueness issue exists because Godot uses resource sharing by default for efficiency. When you assign a material in the editor, the scene file stores a reference to a single material resource. All instances of that scene share the same resource in memory, which means uniform changes propagate to every instance. Calling duplicate() creates a new resource in memory with its own parameter map, breaking the shared reference.

The resource_local_to_scene flag achieves the same thing as duplicate() but is handled automatically by the engine when instances are created. It is the preferred approach when you know at design time that each instance needs independent material parameters.

If you are migrating a Godot 3 project, search your codebase for “set_shader_param” and “get_shader_param” and replace them all. This is one of the most common migration breakages and affects every shader-using script in your project.

Related Issues

If the shader itself is not applying at all (not just the uniforms), the issue may be a shader type mismatch. See Fix: Godot Custom Shader Not Applying to Sprite2D for the canvas_item vs spatial shader type fix.

If you are working with screen-space effects and the coordinates seem wrong even though uniforms are updating correctly, see Fix: Godot Screen-Space Shader Coordinates Off or Inverted.

set_shader_param → set_shader_parameter. Duplicate for unique instances.