\noexpand is the culprit. But removing it is not the full answer.
There's no reason for defining \dblpnct with an argument, but this is not a real problem.
If you are implementing French style spacing before double punctuation, you should be aware that the colon obeys different rules: it should be preceded and followed by a normal interword space. But most important is that you don't want the added space is a feasible line break point.
Defensive code requires also that \unskip is only issued if we're in horizontal mode.
\documentclass{article}
\usepackage{luacode}
\usepackage{etoolbox}
\newrobustcmd\dblpnct[1]{%
\ifhmode\unskip\fi
\nolinebreak#1%
}
\begin{luacode}
function dosub(s)
s = string.gsub(s, '!', '\\dblpnct{\\hspace{0.1em}}!')
s = string.gsub(s, ':', '\\dblpnct{\\space}:')
s = string.gsub(s, ';', '\\dblpnct{\\hspace{0.1em}};')
s = string.gsub(s, '?', '\\dblpnct{\\hspace{0.1em}}?')
return(s)
end
\end{luacode}
\AtBeginDocument{%
\luaexec{luatexbase.add_to_callback("process_input_buffer", dosub, "dosub")}%
}
\begin{document}
Some text ! Or is it a question ? The colon : obeys different ; rules.
Some text! Or is it a question? The colon: obeys different; rules.
\end{document}

And you should also disable this in math mode, or the spacing will be definitely wrong.
\documentclass{article}
\usepackage{luacode}
\usepackage{etoolbox}
\newrobustcmd\dblpnct[1]{%
\ifmmode\else
\ifhmode\unskip\fi
\nolinebreak#1%
\fi
}
\begin{luacode}
function dosub(s)
s = string.gsub(s, '!', '\\dblpnct{\\hspace{0.1em}}!')
s = string.gsub(s, ':', '\\dblpnct{\\space}:')
s = string.gsub(s, ';', '\\dblpnct{\\hspace{0.1em}};')
s = string.gsub(s, '?', '\\dblpnct{\\hspace{0.1em}}?')
return(s)
end
\end{luacode}
\AtBeginDocument{%
\luaexec{luatexbase.add_to_callback("process_input_buffer", dosub, "dosub")}%
}
\begin{document}
Some text ! Or is it a question ? The colon : obeys different ; rules.
Some text! Or is it a question? The colon: obeys different; rules.
Oh, what about math ? $a:b$ and $(a;b)$
\end{document}
Check the result if you remove the \ifmmode conditional.

In order to disable the behavior in the argument to \label and \ref, you can use \ifincsname, but this requires changing the definition of \label.
\documentclass{article}
\usepackage{luacode}
\usepackage{etoolbox}
\newrobustcmd\dblpnct[1]{%
\ifincsname
\else
\ifmmode\else
\ifhmode\unskip\fi
\nolinebreak#1%
\fi
\fi
}
\makeatletter
% latex.ltx, line 4070:
\def\label#1{\@bsphack
\protected@write\@auxout{\let\dblpnct\@gobble}% <-- disable in \label
{\string\newlabel{#1}{{\@currentlabel}{\thepage}}}%
\@esphack}
\makeatother
\begin{luacode}
function dosub(s)
s = string.gsub(s, '!', '\\dblpnct{\\hspace{0.1em}}!')
s = string.gsub(s, ':', '\\dblpnct{\\space}:')
s = string.gsub(s, ';', '\\dblpnct{\\hspace{0.1em}};')
s = string.gsub(s, '?', '\\dblpnct{\\hspace{0.1em}}?')
return(s)
end
\end{luacode}
\AtBeginDocument{%
\luaexec{luatexbase.add_to_callback("process_input_buffer", dosub, "dosub")}%
}
\begin{document}
Some text ! Or is it a question ? The colon : obeys different ; rules.
Some text! Or is it a question? The colon: obeys different; rules.
Oh, what about math ? $a:b$ and $(a;b)$
Here's a reference to page~\pageref{page:x}\label{page:x}.
\end{document}
\unskip\relax{0.1em}!so it just typesets0.1em– David Carlisle Oct 06 '16 at 17:48\noexpandyou should have\nolinebreak. – egreg Oct 06 '16 at 22:13babel-frenchbdoes it. – Oct 07 '16 at 21:55