Integraph

API error codes

Stable machine-readable codes on every 400 response from the ACS concrete and fire endpoints — what each means and how to resolve it.

Overview

Every 400 response from the ACS API carries a ProblemDetails body with a stable code extension field. Client code can branch on code without parsing the human-readable detail string, which is subject to wording changes.


Fire capacity and heat-transfer codes

These codes appear on GET /api/v1/fire/design-options/{designOptionId}/capacity, GET /api/v1/fire/design-options/{designOptionId}/heat-transfer, and the GetFireCapacityByDesignOption / GetFireHeatTransferByDesignOption MCP tools.

steel_class_required

The steelClass parameter was omitted on an endpoint that requires it. Supply "hot_rolled" or "cold_worked".

steel_class_invalid

The supplied steelClass value is not one of the two admissible tokens. ACS maps the token to EN 1992-1-2 Table 3.2a (hot-rolled) or Table 3.2b (cold-worked) by exact ordinal match — a hyphen, a different case, or a fused spelling falls through to this refusal rather than silently selecting the hot-rolled table.

Admissible values: "hot_rolled" · "cold_worked"

The substitution blocked here was ~30 % unconservative in reinforcement yield strength at 500 °C: Table 3.2a gives ky(θ)=0.78k_y(\theta) = 0.78 at 500 °C against Table 3.2b’s ky(θ)=0.60k_y(\theta) = 0.60. The refusal is explicit because that difference is material to an FRL check and would otherwise be entirely invisible — the response echoes the caller’s token verbatim for disclosure, so a wrong token and a correct one look the same on the wire.

Resolution: supply the exact string "hot_rolled" or "cold_worked".

aggregate_type_required

The aggregateType parameter was omitted on an endpoint that requires it, or the persisted FireExposure.AggregateType on the design option is blank. Supply "siliceous" or "calcareous" in the fire panel and re-save.

aggregate_type_invalid

The persisted FireExposure.AggregateType on the design option, or the aggregateType query parameter, is not one of the two admissible tokens. The check is ordinal: a saved value that was valid under an older schema version and no longer parses is refused on read rather than falling through to the siliceous table.

Admissible values: "siliceous" · "calcareous"

This is distinct from aggregate_type_required (which fires when the value is absent) — a non-empty but unrecognised value is refused here so that it can be corrected at the source rather than silently analysed as though it were siliceous.

Resolution: open the Fire panel for the design option, confirm the aggregate type, re-save, and retry.

fire_exposure_not_configured

The design option has no fire exposure saved at all. Both fire reads take the duration, curve, exposed edges and void boundaries from the persisted exposure, and none of them has a defensible substitute. Configure the fire duration, curve and method in the Fire panel and save.

Raised by capacity and heat-transfer, and by both MCP tools.

fire_duration_not_positive

A fire exposure is saved, but its fire-resistance duration is unset, zero or negative. The duration sets how far the thermal solve runs, and with it every temperature in the field and every reduced capacity downstream, so it is never substituted. Set a positive fire-resistance period in the Fire panel and save.

Raised by capacity and heat-transfer, and by both MCP tools. It is checked after fire_exposure_not_configured, so a section with no exposure at all reports that code, not this one.

fire_method_required

The saved fire exposure has no assessment method. The method selects between alternative routes — the AS 3600 Section 5 tabulated check, the EN 1992-1-2 500 °C isotherm method and the advanced fibre method — that are never cumulative (EN 1992-1-2:2004 §4.1), so a persisted null neither fans out nor resolves to isotherm-500. Choose a method in the Fire panel and save.

Raised by capacity and GetFireCapacityByDesignOption only. The heat-transfer read computes the temperature field, which is the same under every method, and never reads it.

fire_design_points_missing

The section has no saved load combination with the Fire limit state, so the capacity read has no design point to check the fire-reduced surface against. Fire capacity is checked against fire-degraded material capacity under the accidental design situation (G+ψQG + \psi Q per AS/NZS 1170.0 Cl 4.2.4 / EN 1990). Add a load combination with limit state Fire in the Applied Loads panel and save.

Not raised for the AS 3600 Section 5 tabulated method, which needs no combination: its Cl 5.6.3(1) load level μfi\mu_{fi} is a table selector, not a demand check. Raised by capacity and GetFireCapacityByDesignOption only.

prestress_losses_unavailable

The section carries tendons, and the post-tensioning loss calculation could not resolve the effective prestress σp.ef\sigma_{p.ef} to one disclosed value — it raised a warning, or it resolved to zero effective prestress on a tendon-bearing section. The detail carries the loss engine’s own warnings.

The PDF report discloses the same state as a warning and runs the fire check without the tendons; the capacity read cannot, because its response has no warnings channel, so a degraded prestress would reach you as a collapsed or zero prestress capacity with nothing on the wire saying so. Correct the tendon and loss inputs — the jacking stress, the strand material, the PT-loss configuration — until the pt-losses derived read resolves cleanly, then re-read.

Raised by capacity and GetFireCapacityByDesignOption, and not for the AS 3600 Section 5 tabulated method, which is a geometry-only check that never reads the effective prestress.

use_upper_conductivity_required

?useUpperConductivity={true|false} was omitted on heat-transfer. EN 1992-1-2:2004 §3.3.3(2) leaves the choice between the upper and lower limit of concrete thermal conductivity to the National Annex; it moves every temperature in the field and every reduced capacity downstream, so it is never defaulted, and it is not resolved from the saved national annex either — the platform holds no verified per-annex conductivity mapping. Checked before the section is read.

Admissible values: true · false

The GetFireHeatTransferByDesignOption MCP tool declares useUpperConductivity as a required boolean parameter, so this code has no MCP counterpart: an omitted value is rejected by the tool’s parameter schema before the tool runs.

fire_request_invalid

The request assembled from the saved section failed the fire engine’s own validation, or the engine rejected an argument while running. The detail carries the engine’s message verbatim. No narrower code is assigned because the cause is whatever the engine found rather than one persisted field.

Raised by capacity and heat-transfer and by both MCP tools, after every named refusal above has been checked — so read the detail before concluding that a named field is at fault.

fire_reinforcement_production_route_undeclared

The section’s reinforcement declares fsy>500f_{sy} > 500 MPa on the AS 3600 path, and the fire check is refused. The grade itself is admissible — this is not a grade refusal.

AS 3600 Cl. 5.3.1(b) Note adopts the EN 1992-1-2 material tables for elevated-temperature steel properties, and those factors are not keyed to a grade: they are normalised ratios selected by the bar’s production route, hot-rolled or cold-worked. Nothing recorded for a grade above 500 MPa says which route it is, and the analysis default — hot-rolled — is the more favourable of the two: at 700 °C the two columns retain 23 % and 12 % of ambient yield respectively. Rather than publish a fire capacity that may assume nearly double the residual strength the bar actually has, the check is withheld.

Record the manufacturer’s production route for the grade, or run the fire check with 500 MPa reinforcement. ACI 318-19 and EN 1992-1-1 sections are unaffected. Unlike the isotherm-500 codes below, this one is method-independent — the advanced fibre method reads the same kyk_y column, so switching tiers does not clear it.

Isotherm-500 codes

The three codes below are raised by capacity and GetFireCapacityByDesignOption only, when the saved method is the EN 1992-1-2:2004 Annex B.1 500 °C isotherm method. Each names the advanced fibre method (EN 1992-1-2:2004 §4.3) as the remedy, because §4.3 integrates the temperature field directly and needs no reduced cross-section.

isotherm500_outside_table_b1

The section lies outside the isotherm method’s declared field of application — EN 1992-1-2:2004 B.1.1(2) and Table B1(a). Two states return this code, and the detail names which, with both numbers:

  • the section’s governing width, measured across a limb between two opposing fire-exposed faces, is below the Table B1(a) minimum for the saved fire-resistance period;
  • the fire-resistance period is above R240, the last row Table B1(a) tabulates, so there is no minimum to measure against.

Below the tabulated width the method does not degrade gracefully: the ratio of the isotherm-500 cool area to the true kc(θ)dx\int k_c(\theta)\,dx is within ±2 % at and above the tabulated row and collapses beneath it, becoming a step function of geometry. Widen the section, shorten the fire-resistance period, or switch to the advanced fibre method, which carries no such limit.

A section with no two fire-exposed faces opposing each other across any limb — a slab exposed on its soffit alone — is not refused. The limit exists to bound the error where two thermal fronts meet, which that exposure geometry rules out; the result carries a disclosure saying the check was inapplicable, not satisfied.

isotherm_carve_not_representable

The 500 °C isotherm carve ran, but the cool region it left cannot be carried downstream as the single effective outline Annex B.1 describes. The detail names which of these occurred:

  • the isotherm boundary could not be closed into an outline, or enclosed no region;
  • the isotherm separates the section into two or more disconnected cool regions — Annex B.1 describes one reduced cross-section and says nothing about one that separates, so no effective section can be formed;
  • the carved outline, or a carved hole, is self-intersecting.

Your authored outline is valid; it is the clipped outline that cannot be analysed. Switch to the advanced fibre method.

This is distinct from isotherm500_outside_table_b1: a section can meet the Table B1(a) minimum width and still separate, because each tabulated row sits above twice the burn-through depth. Table B1 limits the method; connectivity limits the result.

isotherm500_no_effective_concrete

The 500 °C isotherm carve ran and left nothing: the whole gross concrete area has passed 500 °C at the saved fire-resistance period, so the method reduces the section to nothing. The detail names the period and the gross area.

The only capacity left would be that of the bare reinforcement, and that is not a fire capacity for the member. With no surrounding concrete there is no bond to develop the bar forces and no lateral restraint against longitudinal-bar buckling between the ties, so a surface computed from the reinforcement alone would assume a confinement the section no longer has. Switch to the advanced fibre method, which represents a fully-heated section.


Concrete derived-read codes

These codes appear on GET /api/v1/concrete/design-options/{designOptionId}/{quantity} and the corresponding Get*ByDesignOption MCP tools. Some are shared with GET /api/v1/concrete/design-options/{designOptionId}/report, which materialises the same saved section.

design_code_not_set

The design option has no design code saved. Set the design code in the Materials panel.

Also raised by GET /api/v1/concrete/design-options/{designOptionId}/report and the GenerateConcreteReport MCP tool. Before the 2026-09 release the report substituted AS 3600 for a missing design code and rendered, so a PDF stated AS 3600 capacities, ϕ\phi factors and serviceability limits for a section whose code was never chosen.

design_code_not_recognised

The design option’s saved design code is not one of the four this platform implements — AS_3600, ACI_318, EN_1992_1_1 or EN_1992_1_1_2023. The detail names the token it found.

The section editor’s selector cannot produce this state, so it reaches only sections written directly through the API or the MCP tools. Since the 2026-09 release PUT /api/v1/design-options/{designOptionId}/concrete-data rejects an unrecognised token outright, with a 400 keyed on data.designCode; this code covers the rows written before that gate existed. Re-save the section with a supported design code.

Before that release an unrecognised token was accepted and then silently analysed as AS 3600. Only the missing and empty values were ever normalised, so a string such as BS_8110, AS3600 or as_3600 travelled through to the per-code branches, each of which falls back to its AS 3600 arm for a code it does not know — the stress-block parameters, the ULS design yield strength, the squash-load steel stress and the Cl. 1.1.2(d) reinforcement admissibility check among them. The section was designed to a Standard nobody selected, and nothing in the result said so.

This is a different state from design_code_not_set, which says no code was ever chosen and is satisfied by any selection; this one says the code on the row is not a design code, and is satisfied only by correcting it. It is also different from edition_not_implemented, which concerns a code this platform does recognise and is still building.

edition_not_implemented

The design option’s saved design code is EN 1992-1-1:2023, whose analysis modules are still being implemented. The 2023 edition is a separate code path from EN 1992-1-1:2004 — its parameters and national-annex values are held apart so that an amendment to one edition can never perturb the other — and several downstream calculations would otherwise fall through to another code’s mechanics for an edition they do not recognise. The refusal therefore fires before any calculation runs, rather than computing 2004 mechanics under a 2023 label. Select EN 1992-1-1:2004 in the Materials panel to analyse the section.

Raised by the reads that run the section through the analysis runner — analyze, batch-design-check, flexure, interaction, shear, moment-curvature, stress-distribution, stress-check, crack-width, deflection-params, creep-coefficient, pt-losses, pt-stresses and time-dependent — and by the Get*ByDesignOption MCP tools that wrap them.

stress_model_not_set

The quantity requires a concrete stress-strain model (for fibre-based analyses such as moment-curvature), but none is saved on this design option. Select a model in the Materials panel.

:::caution[SLS stress-model keys refused as ULS stressModel — September 2026 (#5319, extended in #5396)] The two SLS constitutive-law identifiers — "linear_elastic_cracked_transformed" and "linear_elastic_cracked_transformed_bischoff" — are refused when supplied as the ULS stressModel. Prior to this fix, both passed the runner’s front-door buildability guard (they exist as named models) and the fibre-integration legs integrated a service-stiffness law (σ = E_c·ε, no ultimate strain, no compression plateau) under every ULS combination, producing φM_u, interaction surfaces and biaxial envelopes integrated from the wrong constitutive law with nothing on the wire naming the substitution (§874).

The SLS constitutive law is always resolved from the section’s slsTensionStiffening setting, not from stressModel. Supplying an SLS key as stressModel on a ULS combination is always a caller error. The refusal applies on every ULS handler that survives — the derived reads (analyze, batch-design-check, flexure, interaction and their peers), the PDF report, and all concrete MCP tools — and produces a 400 whose detail names the key, states why it cannot be the ULS law, and lists the admissible ULS model names. #5319 introduced the refusal on the derived reads and the analysis runner; #5396 extended it to the ULS payload routes of the day and routed the MCP moment-curvature tools through the same runner. Those payload routes are gone: POST /concrete/analyze was retired first (S3), then POST /concrete/flexure and POST /concrete/interaction (#5035) and POST /concrete/batch-design-check (#5038). Each rule they carried is enforced by the derived read that replaced them, against the values saved on the section — which is where #5319 put it in the first place.

Admissible ULS stress-model values: "rectangular" · "hognestad" · "parabolic_rectangular" · "bilinear" · "mander" · "kent_park" · "popovics" · "fib_mc2010" (see stressModel note above for context). :::

member_type_not_set

The quantity requires a member type (beam, column, slab, or wall) but none is saved. Set it in the Materials or Fire panel.

The match is exact — lower-case, no surrounding whitespace. A saved "Column" is refused rather than mapped, because every consumer of the value matches ordinally and would otherwise read it as the "beam" default.

Also raised by GET /api/v1/concrete/design-options/{designOptionId}/report and the GenerateConcreteReport MCP tool. Before the 2026-09 release the report took the "beam" default for a section with none saved, so the PDF published one ductility-check family and one AS 3600 Section 5 axis distance under a heading that named another.

k_phi_not_set

A ULS combination is addressed but no AS 3600 Amd 2:2021 Table 2.2.2 kϕk_\phi class is saved on it. A null would resolve to ϕo=0.60\phi_o = 0.60 — conservative, but a substitution for a Q/GQ/G classification you have not made and one that is invisible in the result. The refusal detail names the combination and the two admissible values, full and reduced, so an API or MCP caller does not have to consult this page to learn what to write. Set the Q/GQ/G class in the Load Combinations panel.

This refusal is raised only where kϕk_\phi can change a number:

  • AS 3600 sections only. kϕk_\phi sets ϕo=0.65kϕ\phi_o = 0.65 k_\phi, an AS 3600 Table 2.2.2(d) quantity. ACI 318 and Eurocode sections never read it, so they are never refused for it — there is no Q/GQ/G class to set on them.
  • flexure additionally requires axial compression. ϕo\phi_o is a bending with axial compression provision, so a combination with N0N^* \le 0 (pure bending or axial tension) is answered normally.
  • analyze, batch-design-check, interaction and mk-interaction refuse for any AS 3600 ULS combination, whatever its NN^*. An interaction surface is a section-level NNMM envelope whose whole compression half is capped at ϕo\phi_o; the combination’s NN^* only places the design point on it. mk-interaction joined this list in the 2026-09 release: until then the fibre M–κ\kappa surface applied Table 2.2.2 item (b) — bending without axial compression — at every axial level it swept, so it never read ϕo\phi_o at all and the class could not change its answer. It now takes item (d) above NubN_{ub} like its rectangular-block sibling, which is what makes an undeclared class a substitution here.
  • The report refuses for any AS 3600 ULS combination too, on the same reasoning: it renders the interaction envelope. Before the 2026-09 release it rendered regardless, so a signed PDF carried every ULS capacity at a substituted ϕo=0.60\phi_o = 0.60 — the largest of the three report gaps closed in that release, because it reached every compression-controlled number on the page rather than one section of it.

A design option that carries applied actions and no load combinations has nowhere to record a class: the analysis pipeline derives a ULS combination from the applied actions, and that derived combination cannot carry one. Such a section is refused under AS 3600 until real load combinations are saved. The section editor does this on its own — it migrates a legacy applied-actions row into a ULS combination when the design option is opened, and writes a Q/GQ/G class onto every ULS row it saves — so this affects rows written through the API or the MCP tools, and rows saved before load combinations existed.

There is no longer a payload endpoint that takes kϕk_\phi on the body. The three that did — POST /api/v1/concrete/flexure (AS 3600 and N>0N^* > 0), POST /api/v1/concrete/interaction (AS 3600, any NN^*) and POST /api/v1/concrete/batch-design-check (AS 3600, on each ULS design action, any NN^*) — were retired in September 2026, in #5035 and #5038 respectively; see batch-design-check: the payload route is retired. Their derived reads raise the identical code under the identical per-route rule, against the class saved on the combination rather than a value on a request body, and the multi-combination read names the offending design actions. Serviceability and fire combinations reach no reader of kϕk_\phi and are never refused for it.

The three payload MCP tools that once followed this rule — CalculateConcreteFlexure, CalculateInteractionDiagram and CalculateBiaxialInteraction — were removed in September 2026 with the routes they wrapped. ConcreteBatchDesignCheck was removed with them in the same release. Their id-addressed peers (GetConcreteFlexureByDesignOption, GetConcreteInteractionByDesignOption, GetConcreteBatchDesignCheckByDesignOption) raise the same code against the class saved on the combination, and return it as an { "error": ... } envelope.

Historical note: before the 2026-08 release the payload tools required kPhi unconditionally, so an ACI 318 or Eurocode section was refused for an AS 3600 classification that does not exist in its code, and a pure-bending AS 3600 flexure request was refused for a parameter it never reads.

sweep_resolution_out_of_range

numAngles, numAxialLevels or numFibres is outside the range the route accepts. The bounds are numAngles 4–72, numAxialLevels 5–50 and numFibres 10–200 on GET /api/v1/concrete/design-options/{designOptionId}/mk-interaction, and numFibres 10–200 on …/sls-stress-field. The GetConcreteMkInteractionByDesignOption MCP tool refuses identically — the bound is one shared check, not a per-surface one.

The detail names the parameter, the value you sent and the range. Nothing is clamped: a clamped resolution integrates a different surface from the one that was requested, and returns it under the resolution you asked for, which is the substitution class this API refuses rather than performs. The same three bounds are what the mkSweepResolution save body accepts, so a resolution that saves is one that reads.

not_applicable_for_combination

The addressed combination’s limit state has no reading for the quantity asked for, and the platform refuses rather than computing one under the wrong heading.

GET .../design-options/{designOptionId}/mk-interaction joins this list from September 2026: the fibre M-κ surface is an ultimate-strength envelope — it integrates the section’s saved ULS constitutive law and applies a capacity reduction factor — so a utilisation published against it under a serviceability or fire heading would be a ULS verdict wearing another limit state’s label. A fire combination is additionally refused because fire capacity is evaluated against the heated section elsewhere, while this route integrates the unheated one. Address a ULS combination.

The same code and the same reasoning apply on the id-addressed MCP tool GetConcreteMkInteractionByDesignOption, which shares the refusal with the REST route rather than reimplementing it.

exposure_class_not_set

The durability-cover derived read requires an exposure class but none is saved. Set it in the Durability panel.

max_aggregate_size_not_set

The durability-cover derived read requires a maximum aggregate size but none is saved. Set it in the Durability panel.

cover_method_incomplete

The design option uses Code-Based cover but has no exposure class saved, so the AS 3600 Section 4 durability cover cannot be derived. The cover stored on the section is the value left over from before Code-Based was selected, and analysing against it would place every bar from a cover you did not specify. Set the exposure class in the Durability panel, or switch the cover mode back to Manual.

Cover is not a presentational input: BarResolver places every bar from it, so it moves the section properties, and through the AS 3600 Cl 3.4.3 shrinkage-restraint term 1+15As/Ag1 + 15 A_s/A_g it moves the effective prestress on a PT section as well.

This refusal is raised only where a code-based cover can actually be derived, on all three counts together:

  • Code-Based cover mode only. A Manual cover is taken verbatim and is never re-derived, so it is never incomplete. A section with no cover method saved is Manual by default.
  • AS 3600 sections only. The code-based derivation is an AS 3600 Section 4 calculation. Selecting Code-Based and then switching the design code to ACI 318 or Eurocode leaves the mode set but inert, and those sections are answered normally rather than refused for a derivation their code does not have. A section with no design code saved at all is answered with design_code_not_set before the cover is ever examined — on the report as well as on the derived reads, since the 2026-09 release. Before it, the report alone substituted AS 3600 at this point and answered such a section with cover_method_incomplete instead, naming the wrong missing field.
  • Only when the exposure class is missing. With one saved, the cover is derived and there is nothing stale to analyse against.

Raised by every concrete derived read except durability-cover, which computes the cover rather than consuming one and answers the missing exposure class with exposure_class_not_set instead. The corresponding Get*ByDesignOption MCP tools return it as an { "error": ... } envelope.

GET /api/v1/concrete/design-options/{designOptionId}/report and the GenerateConcreteReport MCP tool raise it too, and that is the more consequential half. A panel showing a number computed from a stale cover is corrected on the next refresh; a PDF is filed, issued and relied upon. The report was decided on consistency rather than severity: the panels refuse this state, and a report that succeeded where they refuse would read as the authoritative artefact for a section they decline to answer for.

That principle is now general rather than per code. When it was first stated, the report declared this refusal and three others the id-addressed reads make and it did not — design_code_not_set, member_type_not_set and k_phi_not_set — so a section the panels declined for any of those still rendered a PDF. The 2026-09 release closed all three, and the report and the id-addressed reads now refuse the same set.

Every report states its cover basis regardless — code-based against a named exposure classification, or entered directly — in the Cover Clarification block immediately above the per-edge cover table. That disclosure is what makes a code-based cover auditable: the classification it is recorded against is on the page, whether you chose that classification or the editor filled it in for you.

The wording is deliberately recorded against, not derived by the platform. The AS 3600 Section 4 derivation runs in the section editor, which writes the result into the saved cover; the report prints the cover saved with the section and does not re-derive it. An API or MCP caller can therefore save a code-based cover mode, an exposure class and a cover that do not agree, and the report says which classification the cover is filed under rather than vouching for the number against it.

Before the 2026-08 release this state was caught only by a gate in the section editor, so it never reached an API or MCP caller: those callers received numbers computed against the stale cover, with nothing on the wire to distinguish them from numbers computed against a cover you chose.

cover_not_set

The design option has no cover saved at all, so the pattern-placed bars cannot be positioned. Cover is not a presentational input: BarResolver insets pattern and perimeter bars from it, so it moves those bar coordinates and with them the section properties and the lever arm; it is the dominant 3.4c3.4c term in the crack-spacing calculation; it feeds the AS 3600 Cl 3.4.3 shrinkage-restraint term and so the effective prestress on a PT section; and it sets the axis distance the Section 5 fire check is graded against. Before the 2026-08 release it resolved to a 40 mm uniform cover — a plausible mid-range Australian value, which is what made it hard to notice. Set the cover in the Durability panel.

A declared zero cover is a real cover, not an absent one — a machined or exposed-aggregate face legitimately has none — and is analysed normally. Only an absent cover is refused.

This is a different state from cover_method_incomplete, which is why it carries its own code rather than being folded into that one. That refusal says a cover the code-based derivation should have replaced was not replaced, so the section holds a stale but present number; it reads the cover mode, the design code and the exposure class, and never looks at the cover itself. This one says no cover was ever specified, reads the cover alone, and is unaffected by all three. Sharing a code would tell you to set an exposure class when what is missing is the cover.

The section editor always saves a cover, so this state is not reachable through the editor. It reaches sections written directly through the API, and rows saved before the field existed.

Unlike cover_method_incomplete, this refusal does apply to durability-cover. That read is excused from the other one because it computes a cover rather than consuming one — but it still reads the saved cover to place the bars whose seat gives the Cl 5.4 fire axis distance, one of the terms in the Cl 4.10.1 greatest-of it returns. With no cover saved it has no bar positions to work from. The corresponding Get*ByDesignOption MCP tools return it as an { "error": ... } envelope, and the PDF report and GenerateConcreteReport raise it too.

Since the 2026-09 release the material take-off raises it as well — GET /api/v1/design-options/{designOptionId}/metrics, the GetDesignOptionMetrics MCP tool, and the Design Summary card that reads them. A take-off is not a design calculation, and this surface normally drops what it cannot value rather than refusing the request: an unresolvable tendon product costs you the tendon row and leaves the rest of the take-off true. Cover is different, because it is the bar count that goes missing rather than a price. Cover sets the inset run length a spacing-driven pattern distributes its bars along, so with no cover there is no reinforcement quantity to report — and dropping the row would publish a mass, cost and embodied-carbon figure understated by the whole reinforcement contribution, with nothing on the card saying so. A section carrying no reinforcement at all is unaffected: its take-off needs no cover and is served normally.

concrete_grade_not_set

The design option has no concrete grade saved, so fcf'_c cannot be resolved. fcf'_c sets the concrete stress-strain curve, the stress block, ϕMu\phi M_u, the interaction surface, shear, the cracking moment, deflection and the Cl 4.10.1 cover, so every derived read on the section refuses rather than computing on a grade you did not choose. Set the grade in the Materials panel.

rebar_grade_not_set

Two states share this code, and the detail says which. The repairs differ, so read it rather than assuming the first.

The section records no rebar grade at all. fyf_y and EsE_s cannot be resolved; both reach every bar and every fitment that declares no material of its own, and EsE_s also sets the modular ratio used by the serviceability checks. Set the grade in the Materials panel.

One bar or fitment cannot be resolved, and the detail names it (for example Bar pattern:p1:0 … or Fitment s1 …). Since per-element grades each bar and fitment is designed at the material it is placed under, so a section whose own grade is perfectly well set still refuses when one element’s material cannot be resolved. Again two causes:

  • The design holds no record of that material’s properties. It references the material but was saved before the properties were frozen with it. Use Recalculate to take the material’s current properties into the design — saving any edit does the same. Nothing is computed in the meantime, because designing that element at the section’s grade would publish a capacity for steel you did not select for it.
  • The material records no yield strength or elastic modulus. Only a different material fixes that: re-pick it for that element in the reinforcement panel.

rebar_grade_not_qualified_above_500

A reinforcement material used by this section declares fsy>500f_{sy} > 500 MPa without the evidence AS 3600 requires before such a grade is admissible at all. The check runs per distinct grade in use, not once for the section — a section mixing R250N fitments with a qualified S600N longitudinal grade qualifies the 600 and leaves the 250 alone — and the detail names the material at fault, which may not be the section’s own. Cl. 1.1.2(d) extends the Standard to “higher reinforcing steel grades >500 MPa to 800 MPa meeting the requirements of Table 3.2.1”, and Table 3.2.1 has no row above 500 MPa for deformed bar — so those requirements are its Class N column values: uniform elongation εsu0.05\varepsilon_{su} \geq 0.05 and a tensile-to-yield ratio Rm/Re1.08R_m/R_e \geq 1.08, with ductility class N or E, declared on the grade and never inferred from its label. The detail names which of them is missing.

The evidence belongs to the grade, not to the material row that links it: a yield strength typed above the value the grade itself declares carries no evidence for the higher number, and is refused on that ground even when every other field is present. Record the evidence on the grade, or use a catalogued grade at or below 500 MPa.

rebar_yield_outside_as3600_domain

A reinforcement material used by this section — the section’s own grade, or one a bar or fitment declares — puts fsyf_{sy} above 800 MPa, which is outside AS 3600 altogether — Cl. 1.1.2(d) extends the Standard to 800 MPa and no further, so there is no clause covering a stronger grade.

The read refuses rather than designing at the 600 MPa ultimate ceiling. Clipping would design a grade the Standard does not cover, using a number you did not choose, and report it as a normal result.

tendon_jacking_stress_not_set

A persisted tendon carries no jacking stress. It is the engineer’s input and has no defensible substitute, so the read refuses. Set the jacking stress on the tendon.

tendon_material_not_resolved

A persisted tendon resolves to no strand material — the section records no strand area, fpbf_{pb} or EpE_p at either the tendon or the section level. Strand area multiplies directly into the prestress force, so it is never substituted. Select a tendon material in the Materials panel.

combination_required

?combination={id} was omitted on a quantity that is evaluated for one load combination. A load combination is your chosen load case, not an intrinsic property of the section, so the route never picks one for you and never returns all of them — analyze is the all-combinations answer. Name the combination.

Raised by the twelve combination-addressed reads — flexure, interaction, shear, moment-curvature, mk-interaction, stress-distribution, sls-stress-field, stress-check, crack-width, deflection-params, creep-coefficient and pt-stresses — and by the combination-addressed Get*ByDesignOption MCP tools when combinationId is omitted. Checked before the section is read.

This is the concrete usage of the code. The LGS by-id tools raise a combination_required of their own, documented on MCP tools; that page does not describe this refusal, and this section does not describe that one.

fan_out_cap_exceeded

?axis= was omitted on flexure, and the bending-axis domain the read would fan out over holds more values than the platform’s fan-out cap of four. The request is refused rather than truncated: a response carrying some of the axes would be internally consistent, plausible and missing the governing case. Name one axis with ?axis=.

The domain is x and y today, so this refusal is not reachable. It is declared because the cap is a contract: enlarging the domain is a deliberate edit that either raises the cap or starts refusing, never a silent latency and cost regression. Raised by flexure and GetConcreteFlexureByDesignOption only; omitting the axis on today’s domain returns both axes, labelled.

This is the concrete usage of the code. The LGS by-id tools raise a fan_out_cap_exceeded of their own, documented on MCP tools; that page does not describe this refusal.

combination_id_missing

The ?combination={id} you passed does not uniquely address one persisted load combination. Two states return this code, and the detail says which:

  • A combination on the section carries no id at all. No id is minted on read — one would not be stable across requests, and a GET may not write to the section — so the offenders are named by their combination name and index instead.
  • The id you passed addresses more than one combination. Ids are not made unique on save, so a client can persist two combinations sharing one. Nothing is chosen between them: they can carry different limit states, and a quantity whose constitutive law follows the limit state (moment-curvature) would otherwise be computed on whichever happened to be stored first and reported as though it were the one you named. A collision between two other combinations does not block a request that is itself unambiguous.

Both have the same fix: re-save the load combinations from the editor so every one carries a distinct id.

not_applicable_for_combination

The quantity does not apply to the named combination’s limit state. A ULS flexure or shear check is not evaluated for an SLS combination, and vice versa; a fire combination is evaluated against the heated section elsewhere. Address the combination whose limit state the quantity belongs to.

Since September 2026 this code means only that. A quantity whose limit state matched and whose prerequisites were not met on the section as saved returns analysis_not_evaluated_for_inputs below, with the unmet prerequisite named — the two used to share this code and this message, which told engineers holding a correctly matched combination to go and pick a different one.

For the quantities named under each of the three codes below, a check that ran and then crashed or failed to converge, or that never ran at all, returns one of those codes instead of this one. Outside those quantities the split does not apply, and this code still covers everything — including moment-curvature, whose refusal for an unbuildable stress-strain model arrives here with the model error as its detail.

analysis_not_evaluated_for_inputs

The quantity’s limit state matched the combination — the combination is the right one — and the analysis engine did not evaluate it, because the design option as saved does not meet one of the check’s prerequisites. Changing combination will not help; the detail names what to change:

  • shear — the saved combination carries no shear action (VyV^*_y and VxV^*_x both zero), or the saved section carries no fitments;
  • shear — the section’s fitment anchorage is inadequate, so the check is deliberately disabled, not failed, and no capacity is reported. This is the one most directly in your hands: re-detail the fitment hooks and the check runs;
  • interaction — the saved section carries neither bars nor tendons;
  • stress-distribution — the saved stress-strain model is the rectangular stress block, which carries no strain history, or the combination carries no bending action;
  • stress-check, crack-width, deflection-params — the saved combination carries no bending action; crack-width additionally needs a bar or a bonded tendon.

Every one of these is read from the saved row, never from an editor session. A change made on screen that has not finished auto-saving is not yet visible to this read, and the refusal is correct for the design option as it stands.

Where the engine records no reason at all, the detail says so rather than naming a cause it cannot establish. Raised by the same seven quantities as analysis_failed_for_combination below. creep-coefficient is not among them: whether creep applies is a statement about the combination’s SLS class, so a null there is a genuine not_applicable_for_combination.

analysis_failed_for_combination

The quantity was evaluated for the named combination and the calculation failed. The combination is the right one; the check could not be completed on this section. The detail carries the analysis engine’s own description of the failure verbatim — no result is substituted and no partial answer is returned. Report the traceId if the message does not identify something you can change on the section.

Raised by the seven quantities whose analysis is run and caught individually: flexure, interaction, shear, stress-distribution, stress-check, crack-width and deflection-params. creep-coefficient is not among them — its value is built inline with no separate failure path, so a null there is always one of the causes listed above.

analysis_did_not_converge

The quantity was evaluated for the named combination, on the right limit state, and the solver did not converge to the requested action — the section cannot sustain the load on the branch being solved. This is a statement about the section, not about the request.

It is raised by the two quantities whose result is withheld on non-convergence rather than reported at its fallback state:

  • stress-distribution — either the fibre solver’s achieved moment reaches section capacity below the requested MM^*, or it reaches MM^* exactly and no strain state carries NN^* at the converged curvature. Either way the returned strain and stress field would be for a different action than the one asked for. Read the detail — it names which of the two occurred, and the second is not a flexural capacity verdict.
  • deflection-params — the cracked-section solve did not converge, so IefI_{ef} and McrM_{cr} would be left at their defaults.

These two are the only quantities that refuse on non-convergence. stress-check and crack-width run the same cracked-section solver, but they return 200 with their fallback numbers and converged: false rather than refusing — so the absence of this code does not mean a solve converged. On those two, read the converged flag. See Solver convergence for the full split.

Reduce the applied action, or increase the section’s capacity, and re-read.

combination_not_found

The ?combination={id} value does not match any persisted load combination on this design option.

sweep_resolution_required

A quantity with discretisation parameters (mk-interaction requires numAngles, numAxialLevels, and numFibres; sls-stress-field requires numFibres) was called without all required resolution parameters. Each moves the result, so none is defaulted. Provide all required parameters.

bending_plane_required and unknown_bending_plane

The moment-curvature derived read requires ?plane=, which takes exactly one of major, minor or demand. Omitting it returns bending_plane_required; a value outside the set returns unknown_bending_plane rather than falling back to the major axis.

Each plane is a different curve — major and minor are the section’s intrinsic bending axes and demand is the plane of the addressed combination’s own signed MxM^*_x / MyM^*_y resultant — so serving one for an unstated request would be a plausible curve on a basis you did not choose. One plane is returned per call; see API reference — why moment-curvature requires ?plane= for why the three are not returned together.

no_tendons

The pt-losses or pt-stresses derived read was called on a section with no prestressing tendons. These quantities are not defined for reinforced-concrete sections.

time_dependent_config_not_set

The time-dependent derived read requires a saved Time-Dependent configuration but none exists on this design option. Configure the Time-Dependent panel and save.

A configuration that exists but is incomplete is a different answer — time_dependent_config_incomplete — because the remedy is different: it names the fields still to be set.

time_dependent_config_incomplete

The design option has a saved Time-Dependent configuration, but it leaves an input the AEMM run reads undeclared. The refusal names each one. Set them in the Time-Dependent panel and save.

The required fields are the sustained load (axialLoad, moment), the ages (ageAtLoading, ageAtShrinkageStart), the environment and method constants (relativeHumidity, cementType, agingCoefficient) and the snapshot schedule (analysisAges). Each sets the magnitude of the creep and shrinkage reported, and analysisAges additionally sets how many snapshots the response carries — so an absent one changed the shape of the answer, not only its numbers.

Some fields are not required, because 0 on them is a documented sentinel rather than a magnitude: notionalSize (0 = derive h0h_0 as 2Ac/u2A_c/u from the geometry) and the two overrides creepCoefficientOverride and shrinkageStrainOverride (0 = use the model value). environment is optional in the same way — null is the AS 3600 interior k4k_4 class, and it is inert under ACI 318 and Eurocode.

Returned by the time-dependent derived read and its MCP tool. No other read refuses for it — a half-filled creep panel is no reason to withhold ϕVu\phi V_u, and a refusal is still charged. The reads that bundle a time-dependent result rather than projecting one, analyze and batch-design-check, return timeDependent: null instead of substituted numbers — correct, but not yet distinguishable from the null an unconfigured section produces. The PDF report is unaffected too, in the other direction — it degrades rather than refusing, dropping the time-dependent section and carrying this same text as a report warning, so the remaining sections still render. Until the 2026-08 release each absent field resolved instead to a platform literal (relative humidity 65 %, cement type s=0.25s = 0.25, ageing coefficient χ=0.8\chi = 0.8, loading at 28 days, drying from 3 days, zero sustained load), with nothing on the wire distinguishing those from values you chose. The object-level refusal above it named that substitution but could not prevent it: it happened per field, one layer down, on a configuration that passed the gate because the object existed.

prestress_inadmissible

The computed effective prestress on the section is inadmissible — for example, the tendon stress exceeds the strand’s fpuf_{pu}. Correct the tendon inputs.


Geometry codes

These appear on every concrete derived read, the fire capacity read, GET /api/v1/concrete/design-options/{designOptionId}/report and the corresponding MCP tools when the saved section’s geometry cannot be analysed. They are raised by the section-properties step, before any capacity is computed. The shared geometry-validation vocabulary — self_intersection, void_outside_outline and overlapping_regions — is explained in Geometry limitations, which both engines’ geometry kernel shares; the two below are the concrete engine’s own.

degenerate_outline

The outline encloses zero area — its vertices are collinear, or the loop has collapsed onto itself. Such an outline passes the self-intersection scan and would then divide by zero in the centroid integral, with the resulting NaN propagating silently through every downstream result. The threshold is 10910^{-9} mm², which detects exact degeneracy without rejecting any physically drawable section. Redraw the outline in the section editor.

reinforcement_in_void

A bar or tendon lies inside an authored void. Reinforcement in a hole has no concrete to bond to or displace, so its contribution is not defined. The detail names the bar or tendon by its id and coordinates. Move it into the concrete or remove the void.

Only authored voids count. A hole carved by the 500 °C isotherm is not a void: the concrete inside it is physically present, merely above 500 °C and discarded for strength, and EN 1992-1-2:2004 B.1.1(3)(c) is explicit that bars falling outside the reduced cross-section may still be included at their temperature-reduced strength. A bar inside a carved hole is therefore kept on the fire capacity read, at that reduced strength.


Cover refusal codes

These appear on GET /api/v1/concrete/design-options/{designOptionId}/durability-cover and the GetConcreteDurabilityCoverByDesignOption MCP tool when AS 3600 Section 5 does not tabulate an axis distance for the member’s geometry and FRL.

The refusal body carries "resolved": false and a failureReason string naming the specific reason — the member type, FRL, and geometry combination falls outside the tables. Increase the section dimensions, reduce the fire-resistance period, or switch to a calculation method. See Durability cover for the full refusal taxonomy.


  • Fire design — configuring steelClass, aggregateType and supportCondition in the Fire panel
  • Durability cover — cover refusals and the save-then-compute cycle
  • API reference — full route listing with costs and required selectors