juanfont/headscale · error

unmarshalling key JSON: %w (raw: %s)

Error message

unmarshalling key JSON: %w (raw: %s)

What it means

Returned by extractAuthKey in cmd/dev/main.go when json.Unmarshal fails on the output of 'headscale preauthkeys create'. The function expects JSON with a "key" field; non-JSON output (error text, help, empty) causes the unmarshal error, and the offending bytes are echoed in '(raw: ...)'.

Source

Thrown at cmd/dev/main.go:304

	err := json.Unmarshal(data, &user)
	if err != nil {
		return 0, fmt.Errorf("unmarshalling user JSON: %w (raw: %s)", err, data)
	}

	return user.ID, nil
}

// extractAuthKey parses the JSON output of "preauthkeys create" and
// returns the key string.
func extractAuthKey(data []byte) (string, error) {
	var key struct {
		Key string `json:"key"`
	}

	err := json.Unmarshal(data, &key)
	if err != nil {
		return "", fmt.Errorf("unmarshalling key JSON: %w (raw: %s)", err, data)
	}

	if key.Key == "" {
		return "", errEmptyAuthKey
	}

	return key.Key, nil
}

View on GitHub (pinned to 565fd254d0)

Solutions

  1. Inspect the '(raw: ...)' payload in the error to see the actual command output
  2. Run 'headscale preauthkeys create' by hand with the same arguments to surface the real failure
  3. Verify the user exists before creating the preauthkey ('headscale users list')
  4. Rebuild binaries so cmd/dev and the CLI agree on the output format

Example fix

// before
key, err := extractAuthKey(out)

// after
if err != nil {
	return "", fmt.Errorf("preauthkeys create output not parseable (raw: %s): %w", out, err)
}
key, err := extractAuthKey(out)
Defensive patterns

Strategy: validation

Validate before calling

if !json.Valid(out) {
	return "", fmt.Errorf("preauthkeys create emitted non-JSON output: %s", out)
}

Try / catch

if _, err := extractAuthKey(out); err != nil {
	return fmt.Errorf("cannot proceed without auth key: %w", err)
}

Prevention

When it happens

Trigger: The dev tool runs 'headscale preauthkeys create --user ...' and pipes stdout to extractAuthKey. Fails when the command prints an error (e.g., nonexistent user, server unreachable, expired flags) or when the binary version emits a different output format.

Common situations: User referenced by the preauthkey command was not created earlier in the dev flow (step ordering bug); mismatched binary versions between cmd/dev and the headscale CLI; server error text going to stdout instead of stderr.

Related errors


AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15). Data as JSON: /api/errors/19a02681aa934419. Report an issue: GitHub.