grafana/k6 · error

unmarshaling hosts option: %w

Error message

unmarshaling hosts option: %w

What it means

Returned by setFlagsFromK6Options when the JSON produced from options.Hosts cannot be unmarshaled into map[string]string. Because the code round-trips Hosts through JSON (k6 v0.42 hid the internal map), any hosts entry whose value is not a plain string (e.g. a number, array, or object) fails here, before --host-resolver-rules can be built for Chrome.

Source

Thrown at internal/js/modules/k6/browser/chromium/browser_type.go:537

	// Add the host resolver rules.
	//
	// This is done by marshaling the k6 hosts option to JSON and then
	// unmarshaling it to a map[string]string. This is done because the
	// k6 v0.42 changed Hosts from a map to types.NullHosts and doesn't
	// expose the map anymore.
	//
	// TODO: A better way to do this would be to handle the resolver
	// rules by communicating with Chromium (and then using Hosts's
	// Match method) instead of passing the rules via the command line
	// to Chromium.
	var rules map[string]string
	b, err := json.Marshal(k6opts.Hosts)
	if err != nil {
		return fmt.Errorf("marshaling hosts option: %w", err)
	}
	if err := json.Unmarshal(b, &rules); err != nil {
		return fmt.Errorf("unmarshaling hosts option: %w", err)
	}
	for k, v := range rules {
		hostResolver = append(hostResolver, fmt.Sprintf("MAP %s %s", k, v))
	}
	if len(hostResolver) > 0 {
		sort.Strings(hostResolver)
		flags["host-resolver-rules"] = strings.Join(hostResolver, ",")
	}

	return nil
}

// makeLogger makes and returns an extension wide logger.
func makeLogger(ctx context.Context, envLookup env.LookupFunc) (*log.Logger, error) {
	var (
		k6Logger = k6ext.GetVU(ctx).State().Logger
		logger   = log.New(k6Logger, common.GetIterationID(ctx))
	)

View on GitHub (pinned to 93accf6570)

Solutions

  1. Make every hosts value a string of the form 'host:port': hosts: { 'test.k6.io': 'localhost:3000' }
  2. Quote values in YAML/JSON config files so they stay strings
  3. Validate the hosts object before k6 run if generating scripts dynamically
  4. Remove hosts temporarily to confirm launch succeeds, then add mappings back one at a time

Example fix

// before
export const options = { hosts: { 'test.k6.io': 3000 } };

// after
export const options = { hosts: { 'test.k6.io': 'localhost:3000' } };
Defensive patterns

Strategy: validation

Validate before calling

const hosts = { 'test.k6.io': 'localhost:3000' };
for (const [k, v] of Object.entries(hosts)) {
  if (typeof v !== 'string' || !/^[^:]+:\d+$/.test(v)) {
    throw new Error(`hosts['${k}'] must be a 'host:port' string, got: ${JSON.stringify(v)}`);
  }
}

Type guard

function isHostPortString(v) {
  return typeof v === 'string' && /^[^:\s]+:\d+$/.test(v);
}

Prevention

When it happens

Trigger: Launching with options.hosts containing non-string values, e.g. hosts: { 'example.com': 8080 } or a nested object; values that serialize as JSON objects/arrays instead of 'host:port' strings.

Common situations: Script authors writing a port number instead of a full 'host:port' value; copy-pasted hosts blocks from other tools with different value formats; YAML configs where quoting turns values into unexpected types.

Related errors


AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15). Data as JSON: /api/errors/69d92a095242b470. Report an issue: GitHub.