You need to turn on lexical-binding, for that message occurrence in the lambda not to be treated as a free variable. It's a lexical variable local to function cypher/cowsayx-sclock, but within the lambda it's free.
Otherwise, you need to instead substitute the value of variable message in the lambda expression, and use that as a list. Here's a backquoted expression that gives you that list with the message value substituted.
`(lambda ()
(message "%S" ',message)
(shell-command (format "xcowsay %s" (shell-quote-argument ',message)))
But this is less performant than using lexical-binding, which produces a closure for the lambda, encapsulating the value of message.
See the Elisp manual, node Using Lexical Binding.
You can, for example, just put this at the end of a comment line as the first line of your file:
-*- lexical-binding:t -*-
For example, if your code is in file foo.el then this could be its first line:
;;; foo.el --- Code that does foo things. -*- lexical-binding:t -*-