If you look at ?Extract (or ?"[") you'll get the R help for the bracket [] notation, which can use either numbers to specify position, or character values to match the names of the object (column names, in the case of data frames).
i, j, ... indices specifying elements to extract or replace. Indices
are numeric or character vectors or empty (missing) or NULL. Numeric
values are coerced to integer as by as.integer (and hence truncated
towards zero). Character vectors will be matched to the names of the
object (or for matrices/arrays, the dimnames): see ‘Character indices’
below for further details.
If you want to specify by both name & position you need to create a vector that is all strings or all numbers. All the elements in an R vector need to be the same data type. As @zheyuan-li had noted, R will implicitly convert your vector c(1:4, "qsec") to be "1" "2" "3" "4" "qsec", and there are no columns named "1", "2", "3", or "4".
You could use the syntax below to convert the position names to strings so they can be the same type as the "qsec" specification.
mtcars[, c(names(mtcars)[1:4], "qsec")]
# where the c() part = "mpg" "cyl" "disp" "hp" "qsec"
or going the other way, you could convert the name qsec to a number (7) that harmonizes with 1:4:
mtcars[, c(1:4, grep("qsec", colnames(mtcars)))]
# where the c() part = 1 2 3 4 7