Skip to content

Type conversion panic when configuring datasource with numeric dialTimeout #1440

@jamesainslie

Description

@jamesainslie

What happened:

The plugin panics with panic triggered: interface conversion: interface {} is float64, not string when datasources are configured with numeric dialTimeout or timeout values via YAML provisioning or HTTP API.

panic triggered: interface conversion: interface {} is float64, not string

Stack trace:
github.com/grafana/clickhouse-datasource/pkg/plugin.LoadSettings({_, _}, ...)
    /pkg/plugin/settings.go:154 +0x1f98

What you expected to happen:

The datasource should be created successfully and accept numeric timeout values (as JSON/YAML naturally represents numbers as numeric types, not strings).

How to reproduce it (as minimally and precisely as possible):

Option 1: YAML Provisioning

  1. Create a datasource provisioning file with numeric dialTimeout:
apiVersion: 1
datasources:
  - name: ClickHouse Test
    type: grafana-clickhouse-datasource
    url: http://clickhouse:8123
    jsonData:
      server: clickhouse
      port: 9000
      dialTimeout: 10      # Numeric value causes panic
      queryTimeout: 60     # This works fine!
  1. Start Grafana with the provisioning file
  2. Attempt to query the datasource via UI or API
  3. Plugin panics

Option 2: HTTP API

  1. Create datasource via API:
curl -X POST http://localhost:3000/api/datasources \
  -H "Content-Type: application/json" \
  -u admin:admin \
  -d '{
    "name": "ClickHouse Test",
    "type": "grafana-clickhouse-datasource",
    "url": "http://clickhouse:8123",
    "jsonData": {"dialTimeout": 10}
  }'
  1. Attempt to query the datasource
  2. Plugin panics

Screenshots

N/A - This is a backend panic that occurs before UI interaction.

Anything else we need to know?:

Root Cause: When Grafana loads datasource configuration, it converts numeric JSON/YAML values to float64 in the jsonData map. The plugin performs a hard type assertion expecting string at line 154:

if jsonData["dialTimeout"] != nil {
    settings.DialTimeout = jsonData["dialTimeout"].(string)  // PANIC HERE
}

The Fix Already Exists in This Same File!

Ironically, queryTimeout (lines 158-163) already has the correct type-safe implementation:

if jsonData["queryTimeout"] != nil {
    if val, ok := jsonData["queryTimeout"].(string); ok {
        settings.QueryTimeout = val
    }
    if val, ok := jsonData["queryTimeout"].(float64); ok {
        settings.QueryTimeout = fmt.Sprintf("%d", int64(val))
    }
}

Someone fixed queryTimeout but forgot to apply the same fix to dialTimeout and timeout!

Proposed Fix: Apply the same pattern to dialTimeout and timeout:

if jsonData["dialTimeout"] != nil {
    if val, ok := jsonData["dialTimeout"].(string); ok {
        settings.DialTimeout = val
    }
    if val, ok := jsonData["dialTimeout"].(float64); ok {
        settings.DialTimeout = fmt.Sprintf("%d", int64(val))
    }
}

Impact:

  • Breaks all Infrastructure-as-Code deployments (Terraform, Ansible, GitOps)
  • Affects anyone using YAML provisioning with numeric timeout values
  • No workaround available (users cannot control Grafana's type conversion)

Source Code Reference:

Environment:

  • Grafana version: 12.2.0 (likely affects all versions)
  • Plugin version: 4.11.1, 4.11.2, and current main branch
  • OS Grafana is installed on: Linux (Docker), Darwin
  • User OS & Browser: N/A (backend panic)
  • Others: Verified in current main branch source code

Metadata

Metadata

Assignees

Type

No type
No fields configured for issues without a type.

Projects

Status

Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions