hashicorp/nomad · error

tty value is not a boolean: %v

Error message

tty value is not a boolean: %v

What it means

jobRunAction (command/agent/job_endpoint.go:388), reached via JobSpecificRequest for the exec/stream job actions, reads the ?tty= query parameter and parses it with strconv.ParseBool. If the value is non-empty and not a valid Go boolean literal, the request fails with 'tty value is not a boolean'. This rejects the exec request before an allocation is targeted, so no process is started.

Source

Thrown at command/agent/job_endpoint.go:388

	}

	setMeta(resp, &structs.QueryMeta{})

	return out.Actions, nil
}

func (s *HTTPServer) jobRunAction(resp http.ResponseWriter, req *http.Request, jobID string) (any, error) {
	task := req.URL.Query().Get("task")
	action := req.URL.Query().Get("action")
	allocID := req.URL.Query().Get("allocID")

	// Build the request and parse the ACL token
	var err error
	isTTY := false
	if tty := req.URL.Query().Get("tty"); tty != "" {
		isTTY, err = strconv.ParseBool(tty)
		if err != nil {
			return nil, fmt.Errorf("tty value is not a boolean: %v", err)
		}
	}

	args := cstructs.AllocExecRequest{
		JobID:   jobID,
		Task:    task,
		Action:  action,
		AllocID: allocID,
		Tty:     isTTY,
	}
	s.parse(resp, req, &args.QueryOptions.Region, &args.QueryOptions)

	conn, err := s.getWebsocketConnection(req)
	if err != nil {
		return nil, err
	}

	return s.execStream(conn, &args)

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Set the query parameter to a valid boolean literal: tty=true or tty=false (1/0, t/f also accepted).
  2. Omit the tty parameter entirely when not needed; empty/missing means non-TTY (isTTY=false).
  3. Inspect the %v value in the error to see exactly what string was received and correct the client.
  4. If building requests programmatically, encode the value with strconv.FormatBool(isTTY).

Example fix

// before
url := fmt.Sprintf("/v1/job/%s/exec?task=%s&tty=%s", jobID, task, "yes")
// after
url := fmt.Sprintf("/v1/job/%s/exec?task=%s&tty=%s", jobID, task, strconv.FormatBool(true))
Defensive patterns

Strategy: validation

Validate before calling

// Before issuing the job exec request
ttyStr := strconv.FormatBool(isTTY)
if _, err := strconv.ParseBool(ttyStr); err != nil {
    return fmt.Errorf("refusing to send invalid tty param %q", ttyStr)
}
url := fmt.Sprintf("...?task=%s&tty=%s", task, ttyStr)

Type guard

func isValidTTYParam(s string) bool {
    return s == "true" || s == "false"
}

Try / catch

resp, err := http.Post(execURL+"?tty="+ttyStr, "", body)
if err != nil { return err }
if resp.StatusCode == 400 {
    // 'tty value is not a boolean' — re-send without the tty param
    return retryWithoutTTY(execURL, body)
}

Prevention

When it happens

Trigger: GET/POST to the Nomad job exec endpoint (e.g. /v1/client/allocation/... or job exec webSocket route) with ?tty=<bad value> such as tty=yes, tty=on, tty=1.0, or an unexpanded variable. Any non-empty value other than 1/t/T/TRUE/true/True/0/f/F/FALSE/false/False triggers this.

Common situations: Hand-rolled websocket/curl commands for nomad alloc exec equivalents using 'yes'/'no'; UI or scripting wrappers passing string flags; query strings built by concatenation where a config variable contains an unexpected string; users copying '?tty=1' typo'd as '?tty=1x'.

Understand the failure class

Background: "Invalid query parameter" / "Failed to parse value of ...": fixing bad query string parameters across APIs — this error's family across 36 libraries.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/dbeb79c9f5aed647. Report an issue: GitHub.