jackc/pgx · error

statement description failed

Error message

statement description failed: %w

What it means

CopyFrom failed to obtain the statement description (column list and OIDs) for the generated 'select ... from ...' query used to set up the COPY operation. The wrapped error carries the underlying cause from getStatementDescription.

Solutions

  1. Unwrap the error to find the underlying prepare/describe failure (permissions, syntax, missing table)
  2. Verify the table and column names passed to CopyFrom are correct and quoted properly
  3. Check the connecting role has SELECT access on the target table
Defensive patterns

Strategy: try-catch

When it happens

Trigger: Thrown at copy_from.go:155 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of jackc/pgx@ec1a0befd2 (2026-08-04). Data as JSON: /api/errors/5c57124c15289195. Report an issue: GitHub.

Appendix: source

Thrown at copy_from.go:155

	switch ct.mode {
	case QueryExecModeExec, QueryExecModeSimpleProtocol:
		// These modes don't support the binary format. Before the inclusion of the
		// QueryExecModes, Conn.Prepare was called on every COPY operation to get
		// the OIDs. These prepared statements were not cached.
		//
		// Since that's the same behavior provided by QueryExecModeDescribeExec,
		// we'll default to that mode.
		ct.mode = QueryExecModeDescribeExec
		fallthrough
	case QueryExecModeCacheStatement, QueryExecModeCacheDescribe, QueryExecModeDescribeExec:
		var err error
		sd, err = ct.conn.getStatementDescription(
			ctx,
			ct.mode,
			fmt.Sprintf("select %s from %s", quotedColumnNames, quotedTableName),
		)
		if err != nil {
			return 0, fmt.Errorf("statement description failed: %w", err)
		}
	default:
		return 0, fmt.Errorf("unknown QueryExecMode: %v", ct.mode)
	}

	r, w := io.Pipe()
	doneChan := make(chan struct{})

	go func() {
		defer close(doneChan)

		// Purposely NOT using defer w.Close(). See https://github.com/golang/go/issues/24283.
		buf := ct.conn.wbuf

		buf = append(buf, "PGCOPY\n\377\r\n\000"...)
		buf = pgio.AppendInt32(buf, 0)
		buf = pgio.AppendInt32(buf, 0)

View on GitHub (pinned to ec1a0befd2)