Back to posts
AINews

GPT-6 Astra ships with a 403 your retry logic must not retry

OpenAI released GPT-6 Astra on September 3 at $10/$50 per million tokens, with API access for most accounts arriving over the coming days. The migration page removes temperature, top_p and logprobs, drops the none effort level, and moves tool calling to the Responses API. The item that changes how you write an agent loop is misalignment monitoring: a request can come back HTTP 403 with code misalignment_policy_violation, the conversation cannot be resumed, and whether it can be stopped at all depends on which Responses features you use. Here is the coverage table, the error contract, the pricing cliff at 272K tokens, and the greps to run before the model ID reaches you.

OpenAI released GPT-6 Astra on September 3. The model ID is gpt-6-astra. It is rolling out first to enterprises in the Trusted Access Program, and the documentation says API access and the Plus, Pro, Business and Enterprise plans follow "in the coming days". So for most accounts this is a migration you can prepare but not yet run, which is the useful position to be in.

The price is $10 per million input tokens and $50 per million output, the same headline as Claude Fable 5.1 and 2.5 times GPT-5.6 Sol at $4 and $20. Cached input is $1, so a cache hit on Astra costs four times what it costs on Fable 5.1. Cache writes are billed separately at $12.50, which is 1.25 times the input rate. The context window is 1,050,000 tokens with a maximum of 922,000 on input and 128,000 on output. The knowledge cutoff is April 30, 2026.

Those are the numbers. What follows is the part of the documentation that changes code.

The request shape that stops being valid

The API changelog entry lists four changes to consider when migrating from GPT-5.6, and the usage guide turns them into edits:

  • reasoning.effort accepts low, medium, high, xhigh and max. none is not supported. If you run none or minimal today, the guide says to start at low and compare.
  • temperature, top_p and top_logprobs are unsupported and must be removed. On Chat Completions also remove logprobs. On Responses remove message.output_text.logprobs from include.
  • Chat Completions still works, but tool calling requires the Responses API. If your tools go through v1/chat/completions, that path does not carry over.
  • If you are coming from GPT-5.5 or earlier, prompt_cache_retention is replaced by prompt_cache_options.ttl set to "30m".

The first three are the kind of change a grep finds in a minute:

grep -rn --include='*.py' --include='*.ts' --include='*.js' --include='*.go' \
  -E '"temperature"|"top_p"|logprobs|"effort": *"(none|minimal)"|reasoning_effort=.(none|minimal)' .

Anything that grep returns is a request that will fail or be rejected once model says gpt-6-astra. A Chat Completions integration with a tools array is the one to look at hardest, because the fix is not a parameter edit but a migration to Responses, and OpenAI publishes a guide for it.

If you change reasoning effort between turns, the guide asks you to do it with configuration_update items rather than by changing the request-level reasoning.effort, so the cached prefix survives. That is the same cache-preserving pattern Anthropic shipped as a beta header on Fable 5.1 two days earlier. Both vendors now treat effort as something you change inside the conversation, not on the request.

The 403 that is a terminal state

The fourth migration item is the one worth reading twice. Misalignment monitoring reviews model reasoning and actions asynchronously "in consequential contexts, such as transferring sensitive data, accessing sensitive data, or making destructive changes," and it can stop a conversation.

The documentation is explicit about what a stop looks like on the wire. Before streaming begins, the API returns HTTP 403 with error type invalid_request_error and code misalignment_policy_violation. OpenAI tells you to match the code, not the message text. For streaming requests the error can arrive mid-stream, after you have already received output.

Three sentences from that page decide how your agent loop has to be written:

The API does not provide a general way to resume a conversation stopped by misalignment monitoring.

Because monitoring is asynchronous, an action may already have completed before monitoring identifies a concern. A stopped request does not undo earlier actions.

Do not automatically retry the blocked workflow.

Most retry layers treat a 4xx that is not a 429 as either fatal-for-this-call or something to re-issue with a fresh request. Neither is right here. A fresh request on the same conversation is a retry of a blocked workflow. And the correct behaviour is not "fail this call" but "stop dispatching further actions for this conversation, preserve the request and response IDs and the tool calls, and put a human in front of what already ran". That is a new branch in the loop, keyed on a string, and it has to exist before the first 403 arrives.

Whether the stop can happen at all depends on how you carry conversation state. The coverage table:

RequestsBehaviour
Responses API using persisted reasoning, WebSockets, or OpenAI compactionMonitored. The system can identify continuations and block further execution.
Responses API using none of thoseMonitored. Webhooks can receive alerts, but the conversation is not automatically stopped.
Chat CompletionsNot covered by this system. Other safety checks still apply.

Read that as an inventory question. If your agent runs on Responses and preserves reasoning across calls, uses WebSocket mode, or uses OpenAI compaction, you are in the first row and the 403 branch is mandatory. If you build the transcript yourself and send it flat, you are in the second row: you can be alerted but not stopped, and the alert arrives out of band. If you are still on Chat Completions, you are outside the system entirely, and also without tool calling on this model. Moving to Responses to get tools moves you into monitoring at the same time. Those are one decision, not two.

The out-of-band channel is a webhook event, safety.alert.created, carrying an alert ID rather than the alert. You fetch it afterwards:

curl "https://api.openai.com/v1/safety/alerts/${SAFETY_ALERT_ID}" \
  -H "Authorization: Bearer ${OPENAI_API_KEY}"

The key needs the api.safety.alerts.read permission on the same project. The alert carries request_id, response_id, an error_type, a reason that "can be null, including for Zero Data Retention requests," and a request_paused flag. The documentation adds a caveat that belongs in your runbook: request_paused: true means a block was registered. It "does not confirm that execution stopped or that earlier actions were reversed." Your own task state and tool records are the source of truth for what happened.

There is a second gate with its own error code. The cybersecurity checks page, which applies to GPT-5.3-Codex and every newer model, returns cyber_policy when traffic crosses a threshold. If you have not set a per-user safety_identifier, the revocation can apply to the entire organization rather than the one user. That has been documented since earlier models. It matters more now because Astra is the first model OpenAI has designated at the Critical cybersecurity level under its Preparedness Framework, so the thresholds and the review are not theoretical.

The pricing line that only applies above 272K

Two conditions on the price page change the arithmetic for long-context work.

First: "Prompts with more than 272K input tokens are priced at 2x input and cache rates and 1.5x output for the full request." Not the tokens above the line. The full request. A 300,000-token prompt costs $20 per million on every one of its input tokens and $75 per million on the output it produces, while a 270,000-token prompt costs $10 and $50. If you run compaction, that boundary is where to run it. The 1,050,000 window is real, but the price at which you use the upper three quarters of it is double.

Second: Fast mode, which is 2x the applicable rate for roughly 2x speed, "is unavailable for GPT-6 Astra with EU data residency." If you route through a regional endpoint for EU customers and set service_tier: "fast", that combination has no valid answer for this model. Standard processing is the only option there, and regional processing carries its own 10 percent uplift.

Batch and Flex are half of standard, so $5 and $25, which puts batched Astra output at the same price as standard Sol output.

The people this lands on differently

For a team already on Responses with persisted reasoning, this is the smallest migration on the list: three parameters removed, a new error code, a webhook. The 403 branch is the only real work, and it is a day of it.

For anyone with tools on Chat Completions, the migration is not to a model but to an API, and the monitoring comes bundled with it. Budget for that before the model ID shows up in your dashboard.

For indie builders on the consumer tiers, nothing here is actionable until the rollout reaches you. Codex 0.153.1, released the same evening, added the model to its catalog "without changing the default model or showing it in the model picker," so it can be configured but is not the default. When it does arrive, the price is 2.5 times Sol, and the effort floor is low, which is where the cost difference is smallest.

For platform developers who serve many end users through one organization, the safety_identifier question is the one to settle first. Without it, one user's flagged session can take the model away from everyone else on your platform for up to seven days.

What to do this week

Run the grep. Move any tool-calling traffic off Chat Completions if this model is in your plans. Add a branch to the agent loop that treats misalignment_policy_violation as a terminal state for the conversation, logs the IDs, and does not re-issue the request. Register a webhook endpoint for safety.alert.created on each project. Set a per-user safety_identifier if you have not. Then, when the model appears in your account, the change is a model string.

The transferable part is the coverage table. A safety monitor that can halt an agent is not a property of the model. It is a property of how the request carries state, and two integrations calling the same model ID can be on different rows of it. Knowing which row you are on is now part of knowing what your agent can and cannot be stopped from doing.

Vocabulary in /glossary: guardrails, AI agent and rate limit. For the model-ID side of migrations, see model IDs change under you. The /tools entries for ChatGPT and Codex cover the consumer and CLI surfaces.

Get the next post when it ships

One email on Sunday with the new post and a short list of what shipped that week — new guides, tool updates, and a couple of links worth reading.