Thanks to visit codestin.com
Credit goes to github.com

Skip to content

bug: Dynamic Parameters: local module path cannot be resolved (works without dynamic params) #19754

@melvinalmonte

Description

@melvinalmonte

Is there an existing issue for this?

  • I have searched the existing issues

Current Behavior

Version: Coder v2.25.2 (reproduces on both “beta” and “stable" versions 2.24 and 2.25)

When dynamic parameters are enabled for a template, the UI shows a warning that a local Terraform module cannot be resolved and will be ignored:

Module 'module "foo"' in file "main.tf:177,1-13" cannot be resolved. This module will be ignored.

The exact same template (and module) work as expected in:

  • Previous Coder versions, and
  • Templates that do not use dynamic parameters.

The warning blocks/invalidates the module reference in the dynamic-parameters form preview, even though the module is available at runtime. This makes templates that rely on local modules appear broken and can confuse end users.

Image

Relevant Log Output

Expected Behavior

  • Dynamic parameters preview should not fail module resolution, or
  • Coder should run an init/module download step (or otherwise resolve local paths) in whatever environment parses the template for dynamic parameters, or
  • If resolution isn’t possible at preview time, the UI should tolerate unresolved modules without discarding them (no “will be ignored”), since they resolve at apply time in the agent.

Banner doesn't show in non-dynamic parameter templates:

Image

Steps to Reproduce

  1. Use a Terraform module with a local/absolute source path mounted into the workspace (e.g., /opt/terraform-modules). I mounted a volume and referenced it in my template.
resource "null_resource" "dummy_action" {
  provisioner "local-exec" {
    command = "echo 'hello world'"
  }
}

output "message" {
  value = "Foo module dummy action completed"
}
  1. Create a dummy template.
    This is the dummy template I used:
# Local values for convenience
locals {
  workspace_name = lower("${data.coder_workspace.me.owner}-${data.coder_workspace.me.name}")
  
  # Simulated resource status
  fake_resource_status = {
    container_id = "dummy-${substr(md5(local.workspace_name), 0, 12)}"
    ip_address   = "10.0.0.${(data.coder_workspace.me.transition == "start" ? "100" : "0")}"
    status       = data.coder_workspace.me.transition == "start" ? "running" : "stopped"
  }
}

# Dummy resource that represents our "infrastructure"
resource "null_resource" "workspace" {
  count = data.coder_workspace.me.start_count
  
  triggers = {
    workspace_id   = data.coder_workspace.me.id
    workspace_name = local.workspace_name
    cpu            = data.coder_parameter.cpu.value
    memory         = data.coder_parameter.memory.value
    always_run     = timestamp()
  }
  
  # Simulate provisioning
  provisioner "local-exec" {
    command = "echo 'Starting dummy workspace ${local.workspace_name} with ${data.coder_parameter.cpu.value} CPUs and ${data.coder_parameter.memory.value}GB RAM'"
  }
  
  # Simulate cleanup
  provisioner "local-exec" {
    when    = destroy
    command = "echo 'Stopping dummy workspace ${self.triggers.workspace_name}'"
  }
}

# Create a dummy state file to simulate persistence
resource "local_file" "workspace_state" {
  count    = data.coder_workspace.me.start_count
  filename = "/tmp/coder-dummy-${local.workspace_name}.state"
  content  = jsonencode({
    workspace_id = data.coder_workspace.me.id
    owner        = data.coder_workspace.me.owner
    name         = data.coder_workspace.me.name
    created_at   = timestamp()
    resources    = {
      cpu    = data.coder_parameter.cpu.value
      memory = data.coder_parameter.memory.value
      disk   = data.coder_parameter.disk_size.value
    }
    dotfiles_repo = data.coder_parameter.dotfiles_repo.value
    status        = local.fake_resource_status
  })
}

# Coder agent - this is required for Coder to manage the workspace
resource "coder_agent" "main" {
  arch = "amd64"
  os   = "linux"
  
  # Startup script that simulates workspace initialization
  startup_script = <<-EOT
    #!/bin/bash
    set -e
    
    echo "Starting dummy workspace..."
    echo "Resources allocated:"
    echo "   - CPU: ${data.coder_parameter.cpu.value} cores"
    echo "   - Memory: ${data.coder_parameter.memory.value} GB"
    echo "   - Disk: ${data.coder_parameter.disk_size.value} GB"
    
    # Simulate dotfiles setup
    if [ -n "${data.coder_parameter.dotfiles_repo.value}" ]; then
      echo "📁 Would clone dotfiles from: ${data.coder_parameter.dotfiles_repo.value}"
      echo "   (This is a dummy workspace - no actual cloning performed)"
    fi
    
    # Create a dummy process to keep the agent alive
    echo "Dummy workspace ready!"
    echo "This is a simulated environment for testing purposes"
    
    # Keep the agent running
    while true; do
      sleep 30
      echo "Dummy workspace heartbeat at $(date)"
    done &
  EOT
  
  # Connection options
  display_apps {
    vscode          = true
    vscode_insiders = false
    web_terminal    = true
    ssh_helper      = false  # SSH not available in dummy mode
  }
}

# Dummy VS Code app (simulated)
resource "coder_app" "code-server" {
  agent_id     = coder_agent.main.id
  slug         = "vscode"
  display_name = "VS Code (Dummy)"
  url          = "http://localhost:13337?folder=/tmp/dummy-workspace"
  icon         = "/icon/code.svg"
  subdomain    = false
  share        = "owner"
  
  healthcheck {
    url       = "http://localhost:13337/healthz"
    interval  = 30
    threshold = 3
  }
}

# Web terminal (simulated)
resource "coder_app" "terminal" {
  agent_id     = coder_agent.main.id
  slug         = "terminal"
  display_name = "Terminal (Dummy)"
  icon         = "/icon/terminal.svg"
  command      = "echo 'This is a dummy terminal - no real shell available' && cat"
}

# Status page showing dummy info
resource "coder_app" "status" {
  agent_id     = coder_agent.main.id
  slug         = "status"
  display_name = "Workspace Status"
  icon         = "/icon/info.svg"
  url          = "http://localhost:8080"
  subdomain    = false
  share        = "owner"
}

# Metadata for the Coder UI
resource "coder_metadata" "workspace_info" {
  count       = data.coder_workspace.me.start_count
  resource_id = null_resource.workspace[0].id
  
  item {
    key   = "Type"
    value = "Dummy Workspace"
  }
  
  item {
    key   = "CPU"
    value = "${data.coder_parameter.cpu.value} cores (simulated)"
  }
  
  item {
    key   = "Memory"
    value = "${data.coder_parameter.memory.value} GB (simulated)"
  }
  
  item {
    key   = "Disk"
    value = "${data.coder_parameter.disk_size.value} GB (simulated)"
  }
  
  item {
    key   = "Container ID"
    value = local.fake_resource_status.container_id
  }
  
  item {
    key   = "IP Address"
    value = local.fake_resource_status.ip_address
  }
  
  item {
    key   = "Status"
    value = local.fake_resource_status.status
  }
}

# Call the foo module dummy action (THIS WILL CAUSE A WARNING TO OCCUR WHEN DYNAMIC PARAMETERS ARE ENABLED)
module "foo" {
  source = "/opt/terraform-modules"
}

# Show some helpful info in the logs
resource "null_resource" "startup_message" {
  count = data.coder_workspace.me.start_count
  
  provisioner "local-exec" {
    command = <<-EOT
      echo "=========================================="
      echo "DUMMY WORKSPACE CREATED"
      echo "=========================================="
      echo "This is a simulated workspace for testing."
      echo "No real resources have been provisioned."
      echo ""
      echo "Workspace Details:"
      echo "- Name: ${local.workspace_name}"
      echo "- Owner: ${data.coder_workspace.me.owner}"
      echo "- ID: ${data.coder_workspace.me.id}"
      echo ""
      echo "Simulated Resources:"
      echo "- CPU: ${data.coder_parameter.cpu.value} cores"
      echo "- Memory: ${data.coder_parameter.memory.value} GB"
      echo "- Disk: ${data.coder_parameter.disk_size.value} GB"
      echo ""
      echo "Foo module message: ${module.foo.message}"!
      echo "=========================================="
    EOT
  }
} 
  1. Open “Create workspace” and observe the “Module not loaded…” warning shown under Parameters.

Environment

  • Host OS: Debian GNU/Linux 12 (bookworm)
  • Coder version: 2.25.2, 2.24.4

Additional Context

I have tested this on the latest version

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs-triageIssue that require triage

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions