Skip to content

Errors and what to do

PetroScript refuses a mistake where you make it, and most refusals say what to type instead: [code] address: message, then fix:. Read the whole message before trying again; it usually names the nearest right spelling. Most refusals are a ps.PetroScriptError: ps.ModelError (a model that contradicts itself), ps.CompileError, ps.DeckImportError, ps.RunError, ps.results.ResultError (a result asked for wrong), and InputError (a value built wrong, which is also a ValueError). Some are plain Python errors instead: an AttributeError for a name that does not exist, a TypeError for arguments given by position or a well given by name to ps.actions.well, and a bare ValueError from a few checks (ps.lift.generate’s well, datum and axis checks among them). Catch ps.PetroScriptError for PetroScript’s own refusals, and read the message either way.

ps.help(code) explains an issue code, and ps.help(name) any class, keyword or result name.

The examples below edit SPE1 from the opm-tests corpus, a FIELD deck with a producer PROD:

import petroscript as ps
m = ps.load("opm-tests/spe1/SPE1CASE2.DATA")

TypeError: ... __init__() takes 1 positional argument but 2 were given

Section titled “TypeError: ... __init__() takes 1 positional argument but 2 were given”

You passed a name by position: ps.Model("DEMO"), ps.Well("P2", ...). The model’s parts take keywords (only the few that read in order take positions: ps.Event(date, *changes), ps.Every(31, 28), ps.Quantity(3626.0, "psia"), ps.actions.When(condition, then=...)):

well = ps.Well(name="P2", i=5, j=5)

[field.unknown] Produce: no field 'bhp_limt'; did you mean 'bhp_limit'?

Section titled “[field.unknown] Produce: no field 'bhp_limt'; did you mean 'bhp_limit'?”

A misspelt field. The message names the nearest field and lists them all. ps.help(ps.Produce) prints every field with its meaning.

[control.target.count] ps.Produce states no target

Section titled “[control.target.count] ps.Produce states no target”

ps.Produce and ps.Inject take exactly one quantity bare (the target); every other quantity is a *_limit. ps.Produce(well="P", bhp_limit=1000.0) has no target:

control = ps.Produce(well="PROD", oil_rate=2000.0, bhp_limit=1000.0) # target, then a limit

Inject.phase takes one of 'oil', 'water', 'gas', not 'gass'; fix: phase='gas'

Section titled “Inject.phase takes one of 'oil', 'water', 'gas', not 'gass'; fix: phase='gas'”

A word field takes one of its listed words, in lower case or in capitals ("gas" or "GAS"), never mixed ("Gas").

A ps.Quantity of the wrong kind (a length where a pressure goes), or a ps.Quantity where only a bare number is taken (a rule’s threshold, a table column). Bare numbers are in the model’s units: see Units and bare numbers.

[well.control.missing] Well 'P2' has no reservoir control ...

Section titled “[well.control.missing] Well 'P2' has no reservoir control ...”

Every verb (m.set, m.at, m.replace) returns a model that is checked at once, and a well with no control is refused. Setting the well first and its control in a second step fails on the first step. (A well with introduced= a later date builds alone, and is refused at m.check() and ps.compile instead: [well.introduced.unanchored] Well 'M-3' is introduced 2012-01-01 and no perforation or control at that report time names it.) Put the well, its perforations and its control in one m.set, as the refusal’s own fix: line spells it; an injector is the same, with ps.Inject as its control:

try:
m.set("wells/P2", ps.Well(name="P2", i=5, j=5)) # the well alone: refused
except ps.ModelError as refused:
print(refused) # [well.control.missing] ...
start = m.start.isoformat()
m2 = m.set({
"wells/P2": ps.Well(name="P2", i=5, j=5),
f"schedule/{start}/P2/perforation/1": ps.Perforate(well="P2", k=(3, 3), diameter=0.5),
f"schedule/{start}/P2/control": ps.Produce(well="P2", oil_rate=2000.0, bhp_limit=1000.0),
})

[initialization.equil.missing], [fluids.missing], [relperm.missing]

Section titled “[initialization.equil.missing], [fluids.missing], [relperm.missing]”

A ps.Model needs, besides its name, units, start, grid and rock: a fluid (fluid=), its relative permeability (relperm=[...]), an initial state (initial=) and a control for every well. Each refusal’s fix: line names the class to state. The from-scratch waterflood shows a complete model.

InputError: Model: an equation-of-state fluid reads the reservoir temperature

Section titled “InputError: Model: an equation-of-state fluid reads the reservoir temperature”

A model whose fluid is ps.fluid.Compositional needs the reservoir temperature: ps.fluid.Compositional(..., temperature=90.0), or a temperature in the initial state. OPM Flow runs no equation-of-state model; to make a NeqSim lift table, keep your model black-oil and pass the compositional fluid to ps.lift.generate alone (how-to).

[address.unknown] wells/PRODX: no well 'PRODX'; nearest: 'PROD'

Section titled “[address.unknown] wells/PRODX: no well 'PRODX'; nearest: 'PROD'”

An address the model does not hold. The message names the nearest name at the level that missed; m.find("wells/*") lists what is there.

[schedule.date.outside_run] schedule/2030-01-01: the run ends 2024-12-29

Section titled “[schedule.date.outside_run] schedule/2030-01-01: the run ends 2024-12-29”

A change dated after the run’s end. Move the end first, as the fix: line says:

later = m.until("2030-01-01").at("2030-01-01", ps.Shut(well="PROD"))

TypeError: ps.actions.well() takes a well handle, not the name 'PROD'

Section titled “TypeError: ps.actions.well() takes a well handle, not the name 'PROD'”

A rule reads a well through the well itself: ps.actions.well(m.get("wells/PROD")).

AttributeError: ps has no name 'Fluid' (nearest: fluid), ... has no name 'from_neqsim'

Section titled “AttributeError: ps has no name 'Fluid' (nearest: fluid), ... has no name 'from_neqsim'”

The name does not exist; the message names the nearest one when one is close. ps.help() lists every class and namespace, and the API map every public name on one page. Classes that take one of several kinds live in the namespace of the Model keyword: fluid=ps.fluid.BlackOil(...), initial=ps.initial.Equilibrium(...). A NeqSim lift table is ps.lift.generate(...).

AttributeError: 'Model' object has no attribute 'compile'

Section titled “AttributeError: 'Model' object has no attribute 'compile'”

Compiling, loading and opening results are functions of ps, not methods: ps.compile(m), ps.load(path), ps.results.open(folder).

AttributeError: 'Summary' object has no attribute 'add'

Section titled “AttributeError: 'Summary' object has no attribute 'add'”

Values are frozen: nothing has an add. Add a summary request by its address, which keeps the others:

m2 = m.set("summary/field/oil_production_total", "oil_production_total")
m2 = m2.set("summary/wells/PROD", [*m2.summary.wells.get("PROD", ()), "water_cut"])

TypeError: tuple indices must be integers or slices, not str

Section titled “TypeError: tuple indices must be integers or slices, not str”

m.wells is a tuple, in order. Read one well by its address: m.get("wells/PROD").

AttributeError: 'Cartesian' object has no attribute 'permeability_x'

Section titled “AttributeError: 'Cartesian' object has no attribute 'permeability_x'”

The grid holds geometry, the rock holds properties. Read a cell array with m.array("permeability_x"); change it with a grid edit:

tighter = m.apply(ps.grid.Scale(target="permeability_x", by=2.0, cells=ps.Box(k=(3, 3))))

[results.unknown] 'FGPR' is a Flow mnemonic: run.field("gas_production_rate")

Section titled “[results.unknown] 'FGPR' is a Flow mnemonic: run.field("gas_production_rate")”

Results are read by PetroScript’s names, never Flow’s mnemonics. ps.help("FGPR") prints the name. A name the run did not write is refused with the nearest name it did.

DeckImportError: cannot import 'FOOBAR' at bad.DATA:371 ...

Section titled “DeckImportError: cannot import 'FOOBAR' at bad.DATA:371 ...”

ps.load refuses a deck it cannot hold whole, never part of it. The message lists the first gap, then N more gaps: with one line each, led by its code. ps.help("FOOBAR") says whether a class writes that keyword.

CompileError: [preflight.refused] opm-flow refused ... in the pre-flight's dry run

Section titled “CompileError: [preflight.refused] opm-flow refused ... in the pre-flight's dry run”

deck.run() (and deck.check()) asks Flow to read the whole deck before the run, and Flow refused it; the message ends with Flow’s own last lines. ps.compile also raises ps.CompileError on an error row of m.check().

RunError: deck.run(): no opm-flow simulator found: PETROSCRIPT_FLOW is not set and no flow is on PATH

Section titled “RunError: deck.run(): no opm-flow simulator found: PETROSCRIPT_FLOW is not set and no flow is on PATH”

No simulator to run the deck. ps.compile and deck.write still work. See Install and engines; ps.simulators() lists what is found.

RunError: no NeqSim runner: PETROSCRIPT_NEQSIM is not set

Section titled “RunError: no NeqSim runner: PETROSCRIPT_NEQSIM is not set”

ps.lift.generate needs a NeqSim runner. See Install and engines.

RunError: NeqSim refused 24 of 48 points of lift table 1, and a table needs every entry

Section titled “RunError: NeqSim refused 24 of 48 points of lift table 1, and a table needs every entry”

Each refused point is listed with its axis values and the reason. Two common ones:

  • the fluid makes no aqueous phase at standard conditions: a water-cut axis above 0 needs water in the stream. Add an H2O component to the fluid’s components and the composition.
  • the acceleration rule: Ek ... > 0.05 where beggs_brill leaves the momentum term out: the gas moves too fast at that point (a high gas fraction, a high rate or a low THP). Lower those axes or raise the lowest THP. For oil with gas in vertical tubing, correlation="hagedorn_brown" may fill it; for gas alone every correlation refuses it.
  • the well cannot lift ... or a choke: the point is outside what the tubing can flow. Narrow the axes (a lower top rate, a higher THP) to points the well can lift.

PetroScript is licensed under the Apache License 2.0. © 2026 Blauweiss EDV LLC. PetroScript by Blauweiss AI.For AI agents: llms.txt