safety_mode selects which safety instruction Cohere prepends to your prompt. It is a documented enum with three values, it is not a post-generation content filter, and knowing the difference explains exactly what it can and cannot guarantee.
The documented values
Cohere’s safety modes documentation documents three values on the Chat API:
-
"CONTEXTUAL"— the default. The model applies judgement in context: it will engage with difficult subject matter where the context makes the purpose legitimate — medical, legal, fiction, research — while continuing to refuse the core restricted categories. -
"STRICT"— a conservative instruction that avoids sensitive material more broadly, including topicsCONTEXTUALwould engage with. Intended for general-audience-facing products where a false negative is more costly than an unhelpful refusal. -
"OFF"— no safety instruction is added. Availability is restricted and subject to Cohere’s terms; it is not a value every account or every model can use.
{
"model": "command-r-plus-08-2024",
"message": "Summarise the contraindications and overdose risks described in this drug label.",
"documents": [{"id": "spc-1", "text": "..."}],
"safety_mode": "CONTEXTUAL"
}
Cohere has changed both the value set and the availability of safety_mode across model generations, and OFF in particular is gated. Check the documentation above for the model you are calling before designing a flow around a specific value.
It is a preamble, not a filter
This is the part that changes how you should reason about it. The parameter selects a safety preamble — a block of instruction rendered into the system turn ahead of your own — and that is the entire mechanism. There is no separate classifier scoring the output, no moderation endpoint in the path, no scrubbing pass after generation.
Three things follow directly. The safety preamble costs input tokens on every request, so OFF is marginally cheaper per call. Its effect is probabilistic in the way all instruction-following is probabilistic — it shifts the distribution and does not put a wall in front of it. And a refusal produced under STRICT arrives as ordinary generated text with a finish_reason of COMPLETE: there is no distinct refusal field, no error code, and nothing structurally distinguishes “I cannot help with that” from any other answer.
That last point has a practical consequence for anyone building on top. If you need to know that a refusal happened — to route to a human, to log it, to avoid caching it — you are detecting it from the text, and text detection is heuristic. Where it matters, the more robust approach is to ask for a structured decision: a schema with a status field makes a decline machine-readable in a way prose is not.
How it interacts with your own preamble
The safety preamble and your preamble occupy the same system turn, with the safety one first. They are separate: setting your own preamble does not remove the safety instruction, and it does not replace it. This is different from the default assistant preamble, which your preamble does replace — a distinction covered in the preamble parameter.
Because both are instructions in the same turn, they can conflict, and a conflict resolves probabilistically rather than by precedence. A preamble that instructs the model to answer every question without exception, under STRICT, produces inconsistent behaviour on the boundary cases rather than a clean win for either. Choosing the mode that matches your product and then writing a preamble that does not fight it gives far more stable output than trying to override one with the other.
There is one more asymmetry worth naming. Because the mechanism is an instruction rather than a filter, it is subject to the same pressures as any other instruction in the prompt — including adversarial input in a retrieved document or a user message. A safety preamble is not a security boundary and was never presented as one. Treating it as the last line of defence in a system that ingests untrusted text is a category error; it is one input among several to a model that weighs them all.
Which models accept it
safety_mode arrived with the Command R generation and is documented as supported on the August 2024 snapshots and newer. Sending it to an older snapshot is not silently ignored — it is an unrecognised parameter — which is one more reason a request that works against one pinned model can fail against another, and an argument for keeping the model name and the parameters that depend on it in the same configuration. See pinning a dated Cohere model version.
Handling a refusal in code
Because a refusal is ordinary text with an ordinary finish reason, every downstream assumption about the response still applies to it — and several of them are wrong for a refusal specifically.
- Do not cache it. A refusal cached against a prompt hash makes a one-off decline permanent for every future user of that prompt, including after you change the safety mode or the preamble.
- Do not retry it blindly. The same request will be declined again, so a retry loop spends money to produce the same outcome more slowly. If a retry is warranted at all it should change something — the mode, the framing, the routing to a human.
- Do not feed it into the next step of a pipeline. A summarisation step that receives “I cannot help with that” as its input will faithfully summarise the refusal, and the error propagates as content rather than as a failure.
- Do not count it as a success in your metrics. A rise in refusals is a product signal — a change in what users are asking, or in what the model will engage with — and it is invisible if refusals are indistinguishable from answers in your dashboards.
The robust detection strategy is to make the model tell you, rather than to pattern-match its prose. When the task can be expressed as structured output, a required status field with an enum of "answered" and "declined" makes the outcome a field rather than an inference. When it cannot — an open chat surface, where the answer is the product — string matching is what is left, and it should be treated as a heuristic with a false-positive rate rather than as a check. Phrases vary across languages, across model snapshots, and with the preamble you wrote.
Choosing a mode
- Leave it at CONTEXTUAL for internal tools, professional domains and anything where an over-cautious refusal is the expensive failure. A clinical or legal assistant under
STRICTdeclines the questions it exists to answer. - Set STRICT explicitly for consumer-facing surfaces with an unfiltered audience — and set it explicitly rather than relying on a default, so the choice is visible in the request and in code review.
- Treat OFF as a licensing question first. Its availability is governed by Cohere’s terms, not by whether the parameter is accepted, and using it does not transfer responsibility for what the system outputs.
- Do not use it as your only content control. An instruction in the prompt is one layer. If your product has a real content risk, it also needs input checks and output checks that do not depend on the model choosing to comply.
Top comments (0)