hashicorp/nomad · error

tty value is not a boolean: %v

Error message

tty value is not a boolean: %v

What it means

This error is raised by allocExec in command/agent/alloc_endpoint.go:604 when the `tty` query parameter of the exec endpoint is present but strconv.ParseBool cannot parse it. ParseBool only accepts 1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False, so any other value (e.g. "yes", "on", "1 " with whitespace, or an empty-but-present parameter after intermediary rewriting) fails.

Source

Thrown at command/agent/alloc_endpoint.go:604

	return reply.Results, rpcErr
}

func (s *HTTPServer) allocExec(allocID string, resp http.ResponseWriter, req *http.Request) (any, error) {
	// Build the request and parse the ACL token
	task := req.URL.Query().Get("task")
	cmdJsonStr := req.URL.Query().Get("command")
	var command []string
	err := json.Unmarshal([]byte(cmdJsonStr), &command)
	if err != nil {
		// this shouldn't happen, []string is always be serializable to json
		return nil, fmt.Errorf("failed to marshal command into json: %v", err)
	}

	ttyB := false
	if tty := req.URL.Query().Get("tty"); tty != "" {
		ttyB, err = strconv.ParseBool(tty)
		if err != nil {
			return nil, fmt.Errorf("tty value is not a boolean: %v", err)
		}
	}

	args := cstructs.AllocExecRequest{
		AllocID: allocID,
		Task:    task,
		Cmd:     command,
		Tty:     ttyB,
	}
	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. Send only values strconv.ParseBool accepts: true/false, 1/0, t/f, T/F, TRUE/FALSE, True/False.
  2. Coerce your client's boolean to a canonical 'true'/'false' string before building the query string.
  3. Omit the tty parameter entirely when no TTY is desired (absence defaults to false).
  4. Check for accidental whitespace or duplicated parameters (tty=true&tty=yes) in the URL.

Example fix

// before: shell-style boolean
url := fmt.Sprintf(".../exec?allocID=%s&task=%s&command=%s&tty=%v", allocID, task, cmd, "yes")
// after: canonical bool string
url := fmt.Sprintf(".../exec?allocID=%s&task=%s&command=%s&tty=%t", allocID, task, cmd, wantTTY)
Defensive patterns

Strategy: validation

Validate before calling

if _, err := strconv.ParseBool(ttyParam); err != nil {
    return fmt.Errorf("tty must be a ParseBool-compatible bool, got %q", ttyParam)
}

Type guard

func isParseBool(s string) bool {
    _, err := strconv.ParseBool(s)
    return err == nil
}

Prevention

When it happens

Trigger: Calling GET /v1/client/allocation/<allocID>/exec with a non-empty `tty` query parameter that is not a Go-recognized boolean literal — e.g. tty=yes, tty=on, tty=2, or tty=%20 (whitespace).

Common situations: Tooling using shell-style yes/no flags against the Nomad HTTP API; URL builders appending tty with a formatted non-bool value; hand-written clients assuming a wider accepted boolean set than ParseBool supports.

Related errors


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